Customizing Tailwind CSS Theme (Colors, Radius, and Variants) in prompts.chat

You customize the Tailwind CSS theme in prompts.chat by editing prompts.config.ts or setting PCHAT_ environment variables; src/app/layout.tsx converts these values into CSS custom properties like --radius and --primary that components consume via Tailwind's arbitrary value syntax such as rounded-[var(--radius)] and bg-primary.

The prompts.chat codebase implements a runtime theme system that bridges TypeScript configuration with Tailwind CSS utility classes. Instead of modifying tailwind.config.ts and rebuilding your bundle, you control colors, border radius, and UI variants through a centralized configuration object that gets injected into the DOM as CSS variables at runtime.

Theme Configuration Architecture

The theming system centers on a TypeScript configuration object that defines your brand identity, corner roundness, and interface density preferences.

The prompts.config.ts Entry Point

All visual customization starts in prompts.config.ts at the project root. This file exports a configuration object via defineConfig() from src/lib/config/index.ts, which provides full type safety through the ThemeConfig interface.

// prompts.config.ts
import { defineConfig } from "@/lib/config";

export default defineConfig({
  branding: {
    name: "My Prompt Hub",
    logo: "/logo.svg",
  },
  theme: {
    radius: "lg",                // none | sm | md | lg
    variant: "brutal",           // flat | default | brutal
    density: "comfortable",      // compact | default | comfortable
    colors: {
      primary: "#ff4500",        // Hex value converted to OKLCH at runtime
    },
  },
});

The configuration supports three distinct ui variants (flat, default, brutal) and three density modes (compact, default, comfortable), allowing you to adjust visual weight and spacing without writing custom CSS.

Type Definitions and Validation

The ThemeConfig interface and runtime logic reside in src/lib/config/index.ts. This file exports applyEnvOverrides(), which checks for environment variables at runtime and merges them over your static configuration.

Supported environment variables include:

  • PCHAT_THEME_RADIUS – overrides the radius enum
  • PCHAT_THEME_VARIANT – overrides the variant setting
  • PCHAT_THEME_DENSITY – overrides the density setting
  • PCHAT_COLOR – overrides the colors.primary value

Runtime CSS Variable Injection

The conversion from configuration to rendered styles happens server-side in src/app/layout.tsx (lines 116-176), where the layout component transforms your config values into CSS custom properties on the <html> element.

Color Space Conversion with hexToOklch

Inside layout.tsx, the hexToOklch() function converts your configured hex color (e.g., #ff4500) into the OKLCH color space. This conversion ensures perceptual uniformity when the system generates contrast colors and opacity variants. The result is injected as --primary, while a calculated accessible contrast color becomes --primary-foreground.

Radius Mapping via radiusValues

The file defines a lookup table called radiusValues that maps configuration enums to concrete CSS lengths:

const radiusValues = {
  none: "0",
  sm: "0.25rem",
  md: "0.5rem",
  lg: "0.75rem",
};

Your selected radius is written to the --radius CSS variable, which components reference for consistent corner rounding throughout the application.

Variant and Density Classes

Beyond CSS variables, layout.tsx constructs themeClasses by mapping your config to class names like theme-brutal and density-comfortable. These classes are applied directly to the <html> tag, enabling scoped CSS rules that adjust shadows, borders, and internal spacing without requiring Tailwind configuration changes.

Consuming Theme Variables in Components

UI components reference these runtime variables using Tailwind's arbitrary value syntax. In src/components/ui/button.tsx, you will see patterns like:

// src/components/ui/button.tsx
<button 
  className="inline-flex items-center rounded-[var(--radius)] bg-primary text-primary-foreground hover:bg-primary/90 px-4 py-2"
>
  Click me
</button>
  • rounded-[var(--radius)] dynamically applies your configured border radius.
  • bg-primary maps to the --primary variable injected by the layout.
  • text-primary-foreground ensures WCAG-compliant contrast against your primary color.

Because these values are standard CSS custom properties, changes to prompts.config.ts reflect immediately across all components after a page refresh without requiring a Tailwind CSS rebuild.

Environment Variable Overrides

For deployment flexibility—such as running different brands on the same codebase—use the environment override system. Create a .env file in your project root:

PCHAT_THEME_RADIUS=md
PCHAT_THEME_VARIANT=default
PCHAT_THEME_DENSITY=compact
PCHAT_COLOR=#4f46e5

The applyEnvOverrides function in src/lib/config/index.ts (lines 94-100) reads these variables and deep-merges them into the configuration object before layout.tsx processes it. This approach is ideal for Docker deployments or Vercel preview environments where you need environment-specific branding.

Extending the Design System with Custom Radius Values

If the default four radius options are insufficient for your design language, you can extend the system by modifying the lookup table in src/app/layout.tsx:

const radiusValues = {
  none: "0",
  sm: "0.25rem",
  md: "0.5rem",
  lg: "0.75rem",
  xl: "1.25rem",  // Custom addition
  "2xl": "2rem",  // Another custom option
};

Then reference your new value in prompts.config.ts:

theme: { 
  radius: "xl",
  variant: "default",
  density: "default",
  colors: { primary: "#3b82f6" }
}

All components using rounded-[var(--radius)] will automatically adopt the new 1.25rem value, ensuring global consistency without hunting through individual component files.

Summary

  • Configuration centralization: Edit prompts.config.ts to set radius, variant, density, and colors.primary using the ThemeConfig type from src/lib/config/index.ts.
  • Runtime conversion: src/app/layout.tsx uses hexToOklch() and the radiusValues lookup to generate --radius, --primary, and --primary-foreground CSS variables.
  • Component consumption: UI elements reference these variables via Tailwind arbitrary values like rounded-[var(--radius)] and utility classes like bg-primary.
  • Environment flexibility: Use PCHAT_THEME_* and PCHAT_COLOR variables to override settings without touching code, handled by applyEnvOverrides.
  • No rebuild required: The system uses a bundled Tailwind plugin and CSS custom properties, eliminating the need to modify tailwind.config.ts or recompile stylesheets when theming changes.

Frequently Asked Questions

Where is the tailwind.config.ts file in prompts.chat?

The project does not expose a user-editable tailwind.config.ts. Instead, it relies on a bundled Tailwind plugin that maps utility classes (like bg-primary) to CSS variables. These variables are generated at runtime by src/app/layout.tsx based on your prompts.config.ts settings, allowing dynamic theming without CSS rebuilds.

Can I add multiple custom colors beyond the primary color?

The current ThemeConfig interface in src/lib/config/index.ts is optimized for a single primary color. To add secondary or semantic colors (success, warning, danger), extend the ThemeConfig type definition, add the new properties to your prompts.config.ts, and update src/app/layout.tsx (around lines 116-176) to inject additional CSS variables (e.g., --secondary) alongside the existing --primary logic.

How do I change the border radius for only specific components?

Since the global theme sets --radius on the <html> element, all components using rounded-[var(--radius)] share that value. For component-specific overrides, use static Tailwind utility classes (e.g., rounded-md or rounded-none) directly in that component's JSX, or define a new CSS variable in layout.tsx and reference it selectively.

Why does prompts.chat use OKLCH instead of HSL or RGB?

The hexToOklch() function in src/app/layout.tsx converts hex colors to the OKLCH color space because it provides perceptual uniformity—meaning equal changes in lightness values produce visually consistent results regardless of hue. This ensures that generated accessibility colors and opacity variations (like bg-primary/90) remain harmonious and predictable across different brand palettes.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →