Theming

Theme with CSS variables. Change a few values, and everything follows.

CSS Variables

Themes are just CSS variables. Update them once, and components stay in sync across your app. This system uses OKLCH color space for better perceptual uniformity and wider color gamut support.

Default Theme

Start here. These are the defaults that come with ng-cn:

Css
:root {
  --radius: 0.625rem;
  --background: oklch(1 0 0);
  --foreground: oklch(0.145 0 0);
  --card: oklch(1 0 0);
  --card-foreground: oklch(0.145 0 0);
  --popover: oklch(1 0 0);
  --popover-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);
  --destructive-foreground: oklch(0.985 0 0);
  --border: oklch(0.922 0 0);
  --input: oklch(0.922 0 0);
  --ring: oklch(0.708 0 0);
}

.dark {
  --background: oklch(0.145 0 0);
  --foreground: oklch(0.985 0 0);
  --card: oklch(0.205 0 0);
  --card-foreground: oklch(0.985 0 0);
  --popover: oklch(0.205 0 0);
  --popover-foreground: oklch(0.985 0 0);
  --primary: oklch(0.985 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);
  --accent: oklch(0.269 0 0);
  --accent-foreground: oklch(0.985 0 0);
  --destructive: oklch(0.396 0.141 25.723);
  --destructive-foreground: oklch(0.985 0 0);
  --border: oklch(0.269 0 0);
  --input: oklch(0.269 0 0);
  --ring: oklch(0.439 0 0);
}

Color Convention

We use a simple background and foreground convention for colors. background sets the surface. foreground sets the text.

--background

Used for page surfaces.

--foreground

Used for primary text.

--primary

Used for key actions.

--secondary

Used for supporting UI.

--muted

Used for subtle surfaces.

--accent

Used for emphasis.

--destructive

Used for errors and deletions.

--border

Used for borders.

--ring

Used for focus rings.

Custom Theme Configuration

To create a custom theme, you'll need to modify the CSS variables in your ng-cn.scss file. The file structure includes three main parts:

1. CSS Variables (:root and .dark)Define your color palette

Set your colors using OKLCH format for perceptual uniformity:

Css
:root {
  /* Use OKLCH for perceptually uniform colors */
  /* Format: oklch(lightness chroma hue) */

  /* Your brand primary color */
  --primary: oklch(0.6 0.2 250);        /* Blue primary */
  --primary-foreground: oklch(1 0 0);   /* White text on primary */

  /* Supporting colors derived from primary */
  --secondary: oklch(0.95 0.02 250);
  --secondary-foreground: oklch(0.2 0.02 250);
}
2. Tailwind Theme Mapping (@theme inline)Map CSS variables to Tailwind classes

This block connects your CSS variables to Tailwind utility classes:

Css
@theme inline {
  /* Map CSS variables to Tailwind colors */
  --color-background: var(--background);
  --color-foreground: var(--foreground);
  --color-primary: var(--primary);
  --color-primary-foreground: var(--primary-foreground);
  /* ... other color mappings */

  /* Border radius tokens */
  --radius-sm: calc(var(--radius) - 4px);
  --radius-md: calc(var(--radius) - 2px);
  --radius-lg: var(--radius);
  --radius-xl: calc(var(--radius) + 4px);
}
3. Base Layer (@layer base)Apply default styles

Set up base styles that apply theme colors globally:

Css
@layer base {
  * {
    @apply border-border outline-ring/50;
  }
  body {
    @apply bg-background text-foreground;
    font-feature-settings: "rlig" 1, "calt" 1;
  }
  html {
    scroll-behavior: smooth;
  }
  :focus-visible {
    @apply outline-2 outline-ring outline-offset-2;
  }
}

Adding New Colors

Add a variable in CSS, then map it into Tailwind's theme block:

Css
/* Add to your CSS variables */
:root {
  --warning: oklch(0.84 0.16 84);
  --warning-foreground: oklch(0.28 0.07 46);

  --success: oklch(0.72 0.19 145);
  --success-foreground: oklch(0.15 0.05 145);

  --info: oklch(0.68 0.16 245);
  --info-foreground: oklch(1 0 0);
}

/* Add to @theme inline block */
@theme inline {
  --color-warning: var(--warning);
  --color-warning-foreground: var(--warning-foreground);
  --color-success: var(--success);
  --color-success-foreground: var(--success-foreground);
  --color-info: var(--info);
  --color-info-foreground: var(--info-foreground);
}

Now you can use bg-warning, text-warning-foreground, etc.

Understanding OKLCH

OKLCH is a perceptually uniform color space that makes it easier to create harmonious color palettes. The format is:

Css
/* OKLCH Color Format */
oklch(L C H)

/* L = Lightness (0-1) */
oklch(0 0 0)    /* Black */
oklch(0.5 0 0)  /* 50% gray */
oklch(1 0 0)    /* White */

/* C = Chroma (0-0.4+) - Color intensity */
oklch(0.6 0 250)     /* Gray - no chroma */
oklch(0.6 0.1 250)   /* Desaturated blue */
oklch(0.6 0.25 250)  /* Vivid blue */

/* H = Hue (0-360 degrees) */
oklch(0.6 0.2 0)     /* Red */
oklch(0.6 0.2 90)    /* Yellow-green */
oklch(0.6 0.2 180)   /* Cyan */
oklch(0.6 0.2 270)   /* Purple */

Lightness (L)

0 = black, 1 = white. Controls how light or dark the color appears.

Chroma (C)

0 = gray, higher = more saturated. Controls color intensity.

Hue (H)

0-360 degrees. Red ≈ 30, Orange ≈ 70, Yellow ≈ 100, Green ≈ 140, Blue ≈ 260.

Other Color Formats

OKLCH is the default for consistent, modern color. Prefer HSL or RGB? That's fine too:

Css
/* HSL format */
:root {
  --background: 0 0% 100%;
  --foreground: 0 0% 3.9%;
  --primary: 222.2 47.4% 11.2%;
}

/* RGB format */
:root {
  --background: 255 255 255;
  --foreground: 10 10 10;
  --primary: 15 23 42;
}

/* Hex format (not recommended for CSS variables with opacity) */
:root {
  --background: #ffffff;
  --foreground: #0a0a0a;
  --primary: #0f172a;
}

Popular Website Palettes

Get started quickly with color palettes inspired by popular websites and apps. Click on a palette to copy the CSS variables to your clipboard.

shadcn GitHub Vercel Apple OpenAI ClickUp Linear
shadcn ThemeThe default shadcn/ui theme - clean, minimal, and professional
Light Mode

Card Title

Card description text

Primary
Secondary
Destructive
Dark Mode

Card Title

Card description text

Primary
Secondary
Destructive

Color Swatches

Background

Foreground

Primary

Secondary

Muted

Accent

Destructive

Border

Ring

CSS Variables

Css
:root {
  --radius: 0.625rem;
  --background: oklch(1 0 0);
  --foreground: oklch(0.145 0 0);
  --card: oklch(1 0 0);
  --card-foreground: oklch(0.145 0 0);
  --popover: oklch(1 0 0);
  --popover-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);
  --destructive-foreground: oklch(0.985 0 0);
  --border: oklch(0.922 0 0);
  --input: oklch(0.922 0 0);
  --ring: oklch(0.708 0 0);
}

.dark {
  --background: oklch(0.145 0 0);
  --foreground: oklch(0.985 0 0);
  --card: oklch(0.205 0 0);
  --card-foreground: oklch(0.985 0 0);
  --popover: oklch(0.205 0 0);
  --popover-foreground: oklch(0.985 0 0);
  --primary: oklch(0.985 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);
  --accent: oklch(0.269 0 0);
  --accent-foreground: oklch(0.985 0 0);
  --destructive: oklch(0.396 0.141 25.723);
  --destructive-foreground: oklch(0.985 0 0);
  --border: oklch(0.269 0 0);
  --input: oklch(0.269 0 0);
  --ring: oklch(0.439 0 0);
}

Tips for Custom Themes

Maintain Contrast

Always ensure sufficient contrast between background and foreground colors. Use tools like WebAIM's contrast checker to verify accessibility.

Test Both Modes

Always define colors for both light and dark modes. Test your theme thoroughly in both modes to ensure consistency.

Use OKLCH

OKLCH provides perceptually uniform colors. Adjusting lightness values will give predictable results across all hues.

Semantic Naming

Use semantic names like "primary" and "destructive" instead of color names like "blue" and "red" for better maintainability.