Theme Core

The `theme.css` file implements a **generative theme system** that automatically creates a complete semantic color palette from a minimal set of input variables

Theme a subtree with three brand inputs

Changing hue, chroma, and lightness updates components and their contrast colors together.

Local theme

Teal campaign

Only this subtree receives the override.

Preview

More examples

Each example introduces a different part of the shipped API.

Theme inputs propagate through semantic roles

Change accent and surface inputs at a boundary; components consume the resulting roles without custom selectors.

Feedback remains semantic

Overview

The theme.css file implements a generative theme system that automatically creates a complete semantic color palette from a minimal set of input variables. This approach ensures consistent, accessible theming across light and dark modes while providing extensive customization options.

Key Features

  • Generative System: Entire palette generated from core inputs
  • Semantic Color Roles: Meaningful color names for UI consistency
  • Automatic Dark Mode: Seamless adaptation via prefers-color-scheme
  • High Contrast Support: Enhanced accessibility for visual impairments
  • Auto-Context Styling: Automatic text color adjustment for readability
  • OKLCH Color Space: Perceptually uniform color manipulation

Core Input Variables

The theme system starts with a minimal set of customizable variables that define your brand identity:

:root {
/* Core Brand Color (OKLCH) */
--accent-h: 280; /* Hue (0-360°) - e.g., 280 for purple */
--accent-c: 0.15; /* Chroma (0-1) - saturation level */
--accent-l: 60%; /* Lightness (0-100%) - brightness */
/* Theme Configuration */
--surface-saturation: 0.015; /* Surface chroma multiplier */
--surface-lightness-shift: 0%; /* Lift/dim surfaces in either scheme */
--surface-contrast: 65%; /* Separation between surface tiers */
--contrast-factor: 1.0; /* Overall contrast multiplier */
--border-width: 1px; /* Default border width */
--density-factor: 1; /* Shared spacing scale */
--radius-factor: 1; /* Shared corner-radius scale */
/* Color Relationships */
--secondary-hue-shift: 60; /* Degrees to shift for secondary color */
--tertiary-hue-shift: -90; /* Degrees to shift for tertiary color */
}

These inputs control the entire visual identity of your application.

--surface-lightness-shift is deliberately relative rather than an absolute lightness. A value such as 2% lifts both light and dark schemes without forcing either scheme to use the other’s palette. --surface-contrast is a percentage: lower values compress the hierarchy toward the base, while higher values increase the distinction between muted, subtle, default, and overt surfaces.

Density and radius scales

Two unitless factors provide coherent global knobs without replacing individual tokens:

:root {
--density-factor: 0.85; /* Scales --space-* and compatibility --spacing-* tokens. */
--radius-factor: 1.25; /* Scales the non-pill radius hierarchy. */
}

Both default to 1. The preferred radius names are --radius-xs, --radius-sm, --radius-md, --radius-lg, --radius-xl, and --radius-full; the longer --border-radius-* names remain compatible aliases.

The preferred spacing family for new component APIs is --space-2xs through --space-2xl. The tighter --spacing-* family remains available for existing utilities and compact controls; both families now respond to --density-factor.

The documentation header’s collapsed Theme panel edits the important root inputs live, persists explicit overrides locally, and generates copyable :root CSS. Reset removes inline overrides and returns control to the active theme pack and color scheme.

Automatic Palette Generation

From these core inputs, the system automatically generates a complete semantic palette:

Derived Variables

  • Secondary & Tertiary Hues: Calculated shifts from the accent hue
  • Feedback Colors: Predefined hues for success (145°), warning (55°), error (25°), info (245°)
  • Base & Bedrock Colors: Fundamental background colors
  • Surface Hierarchy: Multiple surface levels for visual depth
  • Text Colors: Auto-contrast calculated text colors
  • Interactive States: Hover, active, focus variations

Surface Hierarchy

The system creates a layered surface system for visual hierarchy:

  • --base: Primary background (light in light mode, dark in dark mode)
  • --bedrock: Opposite extreme for highlights/accents
  • --surface-muted/subtle/default/overt: Progressive surface elevations

Bedrock Color Purpose

The bedrock color serves as the “opposite” background:

  • In light mode: Very light (near-white) for subtle highlights
  • In dark mode: Very dark (near-black) for strong contrasts
  • Used for navigation bars, tooltips, and accent backgrounds

Auto-Context Styling

The theme includes intelligent auto-context styling that automatically adjusts text colors based on background:

/* Automatic text color on surfaces */
:where(.bg-base) .text,
:where(.bg-base) p,
:where(.bg-base) h1 { color: var(--text-on-base); }
:where(.bg-bedrock) .text,
:where(.bg-bedrock) p { color: var(--text-on-bedrock); }

This ensures optimal readability without manual color selection, using Lea Verou’s contrast-color algorithm adapted for OKLCH.

Color Architecture

Base Configuration

--accent-h: var(--hue-violet); /* Brand color hue */
--accent-c: 0.15; /* Brand color chroma */
--accent-l: 60%; /* Brand color lightness */

Derived Colors

  • Secondary/Tertiary: Calculated hue shifts from accent
  • Feedback Colors: Success, warning, error, info with predefined hues
  • Surface Hierarchy: Multiple surface levels for depth

Color Role System

Surface Colors (Background Hierarchy)

overt > default > base > subtle > muted
  • --surface-overt: Most prominent (cards, panels)
  • --surface-default: Standard surfaces
  • --surface-subtle: Subtle backgrounds
  • --surface-muted: Disabled/low-contrast states

Text Colors (Foreground Hierarchy)

overt > default > subtle > muted
  • --text-overt: Headings, strong text
  • --text-default: Body text
  • --text-subtle: Secondary text
  • --text-muted: Disabled/placeholder text

Accent Colors (Brand Variations)

  • --accent: Primary brand color
  • --accent-subtle: Lighter variant
  • --accent-overt: Darker variant
  • --accent-muted: Desaturated variant

Light Mode Theme

Surface System

--base: oklch(97.5% 0.015 250); /* Near-white background */
--surface-default: oklch(94% 0.12 250); /* Card backgrounds */
--surface-subtle: oklch(95% 0.105 250); /* Subtle surfaces */

Text System

--text-default: oklch(20% 0.2 250); /* High contrast body text */
--text-subtle: oklch(35% 0.18 250); /* Secondary text */
--text-overt: oklch(10% 0.22 250); /* Heading text */

Interactive Elements

--text-link: oklch(from var(--accent) calc(l + var(--l-delta-1-down)) ...);
--highlight-bg-subtle: oklch(from var(--base) calc(l + var(--l-delta-3-down)) ...);

+## Explicit Light, Dark, And System Modes

Automatic mode is the default. Set data-color-scheme on the root element when an application offers its own theme control:

<html data-color-scheme="dark">

The accepted values are light and dark. Remove the attribute to return to prefers-color-scheme:

const root = document.documentElement;
root.dataset.colorScheme = "light";
root.dataset.colorScheme = "dark";
delete root.dataset.colorScheme; // System preference

This is separate from data-theme: color scheme chooses light or dark contrast, while data-theme="ocean" (or another brand) chooses the palette. Set the attribute before first paint when persisting the user’s choice so native controls do not flash in the wrong mode.

Dark Mode Theme

Inverted Surfaces

--base: oklch(22% 0.02 250); /* Dark background */
--surface-default: oklch(25% 0.02 250); /* Elevated surfaces */
--bedrock: oklch(95% 0.007 250); /* Light text/highlights */

Adjusted Text Colors

--text-default: oklch(88% 0.008 250); /* Light body text */
--text-subtle: oklch(75% 0.01 250); /* Muted text */
--text-overt: oklch(95% 0.006 250); /* Bright headings */

Enhanced Shadows

--shadow-color-dark: 220 20% 90%;
--shadow-sm: 0 1px 2px oklch(from hsl(var(--shadow-color-base)) ...);

High Contrast Mode

Enhanced Contrast

--contrast-factor: 1.3; /* Increased contrast multiplier */
--l-threshold: 0.6; /* Adjusted lightness threshold */
--border-width: 1.5px; /* Thicker borders */

Focus Enhancements

--focus-ring-width: 3px; /* More visible focus rings */
--outline-focus: oklch(0.5 0.3 var(--accent-h)); /* High contrast focus */

Color Calculation System

Dynamic Adjustments

Colors are calculated using the engine’s delta system:

--accent-subtle: oklch(from var(--accent) calc(l + var(--l-delta-2)) calc(c + var(--c-delta-1-down)) h);

Auto-Contrast Text

Text colors automatically adjust for readability:

--text-on-accent: /* Calculated by --contrast-text-for-bg mixin */

Feedback Color System

Semantic Colors

  • Success: Green tones for positive actions
  • Warning: Orange/amber for caution
  • Error: Red for errors/danger
  • Info: Blue for informational content

Surface Variants

--surface-success: oklch(from var(--success) calc(l + var(--l-delta-11)) ...);
--outline-success: oklch(from var(--success) calc(l + var(--l-delta-2-down)) ...);

Component-Specific Roles

Form Elements

--input-focus-bg: transparent;
--input-hover-border-color: var(--outline-overt);
--indicator-color: var(--text-on-accent); /* Checkmarks */

Tables

--table-background: color-mix(in oklch, var(--surface-default) 45%, var(--base));
--table-border-color: color-mix(in oklch, var(--outline-subtle) 65%, transparent);
--table-divider-color: color-mix(in oklch, var(--outline-subtle) 55%, transparent);
--table-heading-background: color-mix(in oklch, var(--surface-subtle) 55%, var(--base));
--table-stripe-background: color-mix(in oklch, var(--surface-muted) 40%, var(--base));
--table-hover-background: color-mix(in oklch, var(--surface-subtle) 75%, var(--base));
--table-selected-background: color-mix(in oklch, var(--accent-muted) 72%, var(--base));
--table-footer-background: color-mix(in oklch, var(--surface-subtle) 35%, var(--base));
--table-scrollbar-color: var(--outline-default);

Code Blocks

--code-block-bg: var(--surface-subtle);
--code-inline-bg: var(--surface-muted);
--code-inline-border: transparent;

Inline code uses the faint surface background without a border by default. Wrapped inline code uses cloned box decoration so its padding and background are not clipped at line edges. kbd and samp retain their bordered treatment.

Scrollbars

Scrollable regions inherit quiet, theme-aware scrollbars without hiding native scroll behavior. Customize --scrollbar-size, --scrollbar-width, --scrollbar-track, --scrollbar-thumb, --scrollbar-thumb-hover, and --scrollbar-radius.

Anchor Positioning

--anchor-offset: 0.5rem; /* Spacing between anchored elements */
--anchor-max-width: 20rem; /* Maximum width for anchored elements */
--anchor-z-index: 1000; /* Z-index for anchored elements */

Customization

Brand Color Override

:root {
--accent-h: 280; /* Custom brand hue */
--secondary-hue-shift: 60; /* Adjust secondary relationship */
--accent-c: 0.18; /* Custom chroma */
}

Theme Extension

:root {
--custom-surface: oklch(90% 0.05 300);
--custom-text: oklch(15% 0.15 300);
}

Dark Mode Customization

@media (prefers-color-scheme: dark) {
:root {
--accent-l: 70%; /* Brighter accent in dark mode */
--surface-c: 0.025; /* Higher contrast surfaces */
}
}

Integration with Framework

Mixin Dependencies

The theme uses mixins from mixins.css:

  • --surface-role(): Applies surface color sets
  • --contrast-text-for-bg: Calculates readable text colors
  • --feedback-role(): Applies semantic color schemes

Engine Integration

Uses delta calculations from engine.css:

  • --l-delta-*: Lightness adjustments
  • --c-delta-*: Chroma adjustments

Component Application

Components consume theme variables:

.my-component {
background: var(--surface-default);
color: var(--text-default);
border: var(--border-width) solid var(--outline-default);
}

Accessibility Considerations

Contrast Ratios

  • WCAG AA Compliance: Minimum 4.5:1 for normal text
  • WCAG AAA: 7:1 for enhanced contrast
  • Dynamic Calculation: Colors adjust based on background

Color Independence

  • Not Color-Dependent: UI works in monochrome
  • Focus Indicators: High contrast focus rings
  • Text Alternatives: Semantic color names

Performance

CSS Variables

  • Static Resolution: Colors calculated at parse time
  • Inheritance: Efficient cascade resolution
  • Minimal Runtime: No JavaScript color calculations

Dark Mode Switching

  • Native Support: Uses prefers-color-scheme
  • Smooth Transitions: CSS transitions between modes
  • No Flash: Prevents FOUC with proper initial values

Browser Support

The theme’s relative OKLCH derivations set the complete Browser Support baseline. Applications targeting older engines must supply static semantic tokens or compile the theme; feature queries remain appropriate for optional enhancements.

Best Practices

Theme Design

  • Semantic Naming: Use purpose over appearance
  • Consistent Ratios: Maintain relationships across modes
  • Testing: Verify in both light and dark modes

Customization

  • Override Strategically: Change base values, not derived ones
  • Document Changes: Comment custom hue values
  • Test Contrast: Ensure accessibility compliance

Maintenance

  • Version Control: Track theme changes
  • User Feedback: Monitor accessibility issues
  • Browser Updates: Leverage new color features

Export from the Theme creator

Open Theme in the site header to edit brand relationships, feedback hues, density, radius, prose typography, UI typography, and heading character. Start from Clean, Compact, or Editorial, then copy or download the result.

@import "css-tags";
@import "./my-theme.css";

The generated file uses @layer css-tags-theme and is designed to load after CSS Tags. It can target the entire document or a reusable [data-theme="name"] boundary. The editor exports only authored inputs, not hundreds of derived colors, so the library continues to calculate contrast and semantic surfaces.