Skip to main content

Theming

Blocks uses CSS variables and the OKLCH color space to provide a powerful, flexible theming system with built-in dark mode support.

Theme Configuration

The theme is configured in components.json:
{
  "style": "new-york",
  "tailwind": {
    "baseColor": "neutral",
    "cssVariables": true
  }
}
CSS variables mode allows you to change themes without rebuilding your application.

CSS Variables Structure

All theme variables are defined in app/globals.css using the OKLCH color space:
:root {
  --radius: 0.625rem;
  --background: oklch(1 0 0);
  --foreground: oklch(0.145 0 0);
  --primary: oklch(0.205 0 0);
  --primary-foreground: oklch(0.985 0 0);
  --secondary: oklch(0.97 0 0);
  --secondary-foreground: oklch(0.205 0 0);
  --muted: oklch(0.97 0 0);
  --muted-foreground: oklch(0.556 0 0);
  --accent: oklch(0.97 0 0);
  --accent-foreground: oklch(0.205 0 0);
  --destructive: oklch(0.577 0.245 27.325);
  --border: oklch(0.922 0 0);
  --input: oklch(0.922 0 0);
  --ring: oklch(0.708 0 0);
}

Dark Mode

Dark mode is implemented using a .dark class with overridden variables:
.dark {
  --background: oklch(0.145 0 0);
  --foreground: oklch(0.985 0 0);
  --primary: oklch(0.922 0 0);
  --primary-foreground: oklch(0.205 0 0);
  --secondary: oklch(0.269 0 0);
  --secondary-foreground: oklch(0.985 0 0);
  --muted: oklch(0.269 0 0);
  --muted-foreground: oklch(0.708 0 0);
  --border: oklch(1 0 0 / 10%);
  --input: oklch(1 0 0 / 15%);
}

Color Palette Variables

1

Primary colors

Used for main actions and emphasis:
  • --primary: Primary brand color
  • --primary-foreground: Text color on primary background
<Button className="bg-primary text-primary-foreground">
  Primary Action
</Button>
2

Secondary colors

Used for less prominent elements:
  • --secondary: Secondary color
  • --secondary-foreground: Text on secondary background
<Button variant="secondary" className="bg-secondary text-secondary-foreground">
  Secondary Action
</Button>
3

Muted colors

Used for disabled states and subtle elements:
  • --muted: Muted background
  • --muted-foreground: Muted text
<p className="text-muted-foreground">Secondary information</p>
4

Accent colors

Used for hover states and highlights:
  • --accent: Accent background
  • --accent-foreground: Text on accent background

Border Radius Customization

Blocks provides four radius sizes using CSS variables:
:root {
  --radius: 0.625rem;
  --radius-sm: calc(var(--radius) - 4px);
  --radius-md: calc(var(--radius) - 2px);
  --radius-lg: var(--radius);
  --radius-xl: calc(var(--radius) + 4px);
}
Access these in your components:
<div className="rounded-lg">Default radius</div>
<div className="rounded-xl">Larger radius</div>

Customizing Your Theme

Changing Colors

Update the CSS variables in app/globals.css to match your brand:
:root {
  --primary: oklch(0.55 0.22 250);
  --primary-foreground: oklch(1 0 0);
}

.dark {
  --primary: oklch(0.65 0.22 250);
  --primary-foreground: oklch(0.15 0 0);
}

Adjusting Border Radius

Change the base radius value to affect all components:
:root {
  --radius: 0.5rem; /* Default: 0.625rem */
}
Use smaller radius values (0.25rem - 0.375rem) for a modern, sharp look, or larger values (0.75rem - 1rem) for a softer appearance.

Chart Colors

Blocks includes chart color variables for data visualization:
:root {
  --chart-1: oklch(0.646 0.222 41.116);
  --chart-2: oklch(0.6 0.118 184.704);
  --chart-3: oklch(0.398 0.07 227.392);
  --chart-4: oklch(0.828 0.189 84.429);
  --chart-5: oklch(0.769 0.188 70.08);
}

.dark {
  --chart-1: oklch(0.488 0.243 264.376);
  --chart-2: oklch(0.696 0.17 162.48);
  --chart-3: oklch(0.769 0.188 70.08);
  --chart-4: oklch(0.627 0.265 303.9);
  --chart-5: oklch(0.645 0.246 16.439);
}
The sidebar has its own set of theme variables:
:root {
  --sidebar: oklch(0.985 0 0);
  --sidebar-foreground: oklch(0.145 0 0);
  --sidebar-primary: oklch(0.205 0 0);
  --sidebar-primary-foreground: oklch(0.985 0 0);
  --sidebar-accent: oklch(0.97 0 0);
  --sidebar-accent-foreground: oklch(0.205 0 0);
  --sidebar-border: oklch(0.922 0 0);
  --sidebar-ring: oklch(0.708 0 0);
}

Theme Inline Configuration

The @theme inline directive maps CSS variables to Tailwind classes:
@theme inline {
  --color-background: var(--background);
  --color-foreground: var(--foreground);
  --color-primary: var(--primary);
  --color-border: var(--border);
  --radius-lg: var(--radius);
}
This allows you to use theme variables directly in Tailwind classes:
<div className="bg-background text-foreground border-border rounded-lg">
  Themed content
</div>

Base Layer Styles

The base layer applies theme variables globally:
@layer base {
  * {
    @apply border-border outline-ring/50;
  }
  body {
    @apply bg-background text-foreground;
  }
}

Dark Mode Variant

A custom dark variant is defined for scoped dark mode styling:
@custom-variant dark (&:is(.dark *));
Use it in your components:
<div className="bg-white dark:bg-gray-900">
  Light background with dark mode support
</div>

Complete Theme Example

Here’s a complete custom theme implementation:
/* Custom brand theme */
:root {
  --radius: 0.5rem;
  
  /* Brand colors */
  --primary: oklch(0.5 0.2 220);
  --primary-foreground: oklch(1 0 0);
  
  /* Surfaces */
  --background: oklch(0.99 0 0);
  --foreground: oklch(0.1 0 0);
  --card: oklch(1 0 0);
  
  /* Interactive */
  --accent: oklch(0.95 0.01 220);
  --accent-foreground: oklch(0.2 0 0);
  
  /* Borders */
  --border: oklch(0.9 0 0);
  --ring: oklch(0.5 0.2 220);
}

.dark {
  --primary: oklch(0.6 0.2 220);
  --background: oklch(0.12 0 0);
  --foreground: oklch(0.98 0 0);
  --card: oklch(0.15 0 0);
  --accent: oklch(0.2 0 0);
  --border: oklch(1 0 0 / 10%);
}
The OKLCH color space provides better color consistency and perceptual uniformity compared to traditional RGB or HSL.

Best Practices

  • Maintain contrast: Ensure sufficient contrast between text and backgrounds (WCAG AA: 4.5:1)
  • Test both modes: Always verify your theme in both light and dark modes
  • Use semantic variables: Reference --primary, --accent, etc. instead of hardcoding colors
  • Preserve accessibility: Keep focus rings and interactive states visible
  • Test with real content: Verify your theme works with actual UI components

Next Steps

Build docs developers (and LLMs) love