Documentation
Styling
Theming

Theming

Creating consistent design systems with CSS variables.

CSS Variables

Define design tokens as CSS variables:

/* styles/globals.css */
@layer base {
  :root {
    /* Colors */
    --background: 0 0% 100%;
    --foreground: 222.2 84% 4.9%;
 
    --primary: 24 95% 53%;
    --primary-foreground: 210 40% 98%;
 
    --secondary: 210 40% 96.1%;
    --secondary-foreground: 222.2 47.4% 11.2%;
 
    --muted: 210 40% 96.1%;
    --muted-foreground: 215.4 16.3% 46.9%;
 
    --accent: 210 40% 96.1%;
    --accent-foreground: 222.2 47.4% 11.2%;
 
    --destructive: 0 84.2% 60.2%;
    --destructive-foreground: 210 40% 98%;
 
    --border: 214.3 31.8% 91.4%;
    --input: 214.3 31.8% 91.4%;
    --ring: 24 95% 53%;
 
    /* Radius */
    --radius: 0.5rem;
  }
 
  .dark {
    --background: 222.2 84% 4.9%;
    --foreground: 210 40% 98%;
 
    --primary: 24 95% 53%;
    --primary-foreground: 210 40% 98%;
 
    --secondary: 217.2 32.6% 17.5%;
    --secondary-foreground: 210 40% 98%;
 
    --muted: 217.2 32.6% 17.5%;
    --muted-foreground: 215 20.2% 65.1%;
 
    --accent: 217.2 32.6% 17.5%;
    --accent-foreground: 210 40% 98%;
 
    --destructive: 0 62.8% 30.6%;
    --destructive-foreground: 210 40% 98%;
 
    --border: 217.2 32.6% 17.5%;
    --input: 217.2 32.6% 17.5%;
    --ring: 24 95% 53%;
  }
}

Using Variables in Tailwind

// tailwind.config.js
module.exports = {
  theme: {
    extend: {
      colors: {
        background: 'hsl(var(--background))',
        foreground: 'hsl(var(--foreground))',
        primary: {
          DEFAULT: 'hsl(var(--primary))',
          foreground: 'hsl(var(--primary-foreground))',
        },
        secondary: {
          DEFAULT: 'hsl(var(--secondary))',
          foreground: 'hsl(var(--secondary-foreground))',
        },
        muted: {
          DEFAULT: 'hsl(var(--muted))',
          foreground: 'hsl(var(--muted-foreground))',
        },
        accent: {
          DEFAULT: 'hsl(var(--accent))',
          foreground: 'hsl(var(--accent-foreground))',
        },
        destructive: {
          DEFAULT: 'hsl(var(--destructive))',
          foreground: 'hsl(var(--destructive-foreground))',
        },
        border: 'hsl(var(--border))',
        input: 'hsl(var(--input))',
        ring: 'hsl(var(--ring))',
      },
      borderRadius: {
        lg: 'var(--radius)',
        md: 'calc(var(--radius) - 2px)',
        sm: 'calc(var(--radius) - 4px)',
      },
    },
  },
};

Usage in Components

<div className="bg-background text-foreground">
  <Button className="bg-primary text-primary-foreground">
    Primary Button
  </Button>
 
  <p className="text-muted-foreground">
    Secondary text
  </p>
 
  <div className="border border-border rounded-lg">
    Card with border
  </div>
</div>

Theme Provider

// components/ThemeProvider.tsx
import { createContext, useContext, useEffect, useState } from 'react';
 
type Theme = 'light' | 'dark' | 'system';
 
interface ThemeContextType {
  theme: Theme;
  setTheme: (theme: Theme) => void;
}
 
const ThemeContext = createContext<ThemeContextType | undefined>(undefined);
 
export const ThemeProvider = ({ children }: { children: React.ReactNode }) => {
  const [theme, setTheme] = useState<Theme>('system');
 
  useEffect(() => {
    const root = window.document.documentElement;
    root.classList.remove('light', 'dark');
 
    if (theme === 'system') {
      const systemTheme = window.matchMedia('(prefers-color-scheme: dark)')
        .matches ? 'dark' : 'light';
      root.classList.add(systemTheme);
    } else {
      root.classList.add(theme);
    }
  }, [theme]);
 
  return (
    <ThemeContext.Provider value={{ theme, setTheme }}>
      {children}
    </ThemeContext.Provider>
  );
};
 
export const useTheme = () => {
  const context = useContext(ThemeContext);
  if (!context) throw new Error('useTheme must be used within ThemeProvider');
  return context;
};

Rules

  1. No inline styles — Use Tailwind classes only
  2. Extract patterns — Create reusable components for common patterns
  3. Mobile-first — Start with mobile styles, add breakpoints for larger screens
  4. Design tokens — Use CSS variables for consistent theming
  5. Spacing scale — Use consistent spacing: 4, 8, 12, 16, 24, 32, 48, 64