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:
: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.
--backgroundUsed for page surfaces.
--foregroundUsed for primary text.
--primaryUsed for key actions.
--secondaryUsed for supporting UI.
--mutedUsed for subtle surfaces.
--accentUsed for emphasis.
--destructiveUsed for errors and deletions.
--borderUsed for borders.
--ringUsed 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:
Set your colors using OKLCH format for perceptual uniformity:
: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);
}This block connects your CSS variables to Tailwind utility classes:
@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);
}Set up base styles that apply theme colors globally:
@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:
/* 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:
/* 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:
/* 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.
Card Title
Card description text
Card Title
Card description text
Color Swatches
Background
Foreground
Primary
Secondary
Muted
Accent
Destructive
Border
Ring
CSS Variables
: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
Always ensure sufficient contrast between background and foreground colors. Use tools like WebAIM's contrast checker to verify accessibility.
Always define colors for both light and dark modes. Test your theme thoroughly in both modes to ensure consistency.
OKLCH provides perceptually uniform colors. Adjusting lightness values will give predictable results across all hues.
Use semantic names like "primary" and "destructive" instead of color names like "blue" and "red" for better maintainability.