Customize colors, typography, and spacing in Classic Theme
Tags: theming customization design-tokens
Classic Theme uses CSS custom properties (variables) for theming, making it easy to customize colors, typography, and spacing.
How Theming Works
Classic Theme's theming system is built on three layers:
- Design Tokens - Core values defined in
@classic-homes/theme-tokens - CSS Variables - Runtime customizable properties
- Tailwind Preset - Utility classes mapped to CSS variables
Customizing Colors
Override CSS variables in your global stylesheet:
:root {
/* Primary color */
--primary: 220 90% 56%;
--primary-foreground: 0 0% 100%;
/* Background colors */
--background: 0 0% 100%;
--foreground: 222 47% 11%;
/* Card colors */
--card: 0 0% 100%;
--card-foreground: 222 47% 11%;
/* Muted colors */
--muted: 210 40% 96%;
--muted-foreground: 215 16% 47%;
/* Border and input */
--border: 214 32% 91%;
--input: 214 32% 91%;
--ring: 220 90% 56%;
}Colors use HSL values without the hsl() wrapper. This allows Tailwind to add opacity modifiers like bg-primary/50.
Dark Mode
Add dark mode support by defining variables for the dark color scheme:
@media (prefers-color-scheme: dark) {
:root {
--background: 222 47% 11%;
--foreground: 210 40% 98%;
--card: 222 47% 11%;
--card-foreground: 210 40% 98%;
--primary: 217 91% 60%;
--primary-foreground: 222 47% 11%;
--muted: 217 33% 17%;
--muted-foreground: 215 20% 65%;
--border: 217 33% 17%;
--input: 217 33% 17%;
--ring: 217 91% 60%;
}
}Or use a class-based approach:
.dark {
--background: 222 47% 11%;
--foreground: 210 40% 98%;
/* ... other dark mode variables */
}Available CSS Variables
Semantic Colors
| Variable | Description |
|---|---|
--background |
Page background color |
--foreground |
Default text color |
--card |
Card background color |
--card-foreground |
Card text color |
--popover |
Popover background color |
--popover-foreground |
Popover text color |
--primary |
Primary action color |
--primary-foreground |
Text on primary color |
--secondary |
Secondary action color |
--secondary-foreground |
Text on secondary color |
--muted |
Muted/subtle background |
--muted-foreground |
Muted text color |
--accent |
Accent/highlight color |
--accent-foreground |
Text on accent color |
--destructive |
Destructive/error color |
--destructive-foreground |
Text on destructive color |
Status Colors
| Variable | Description |
|---|---|
--success |
Success state color |
--success-foreground |
Text on success color |
--warning |
Warning state color |
--warning-foreground |
Text on warning color |
--error |
Error state color |
--error-foreground |
Text on error color |
--info |
Info state color |
--info-foreground |
Text on info color |
UI Elements
| Variable | Description |
|---|---|
--border |
Default border color |
--input |
Input border color |
--ring |
Focus ring color |
--radius |
Default border radius |
Control colors
| Variable | Description |
|---|---|
--secondary |
Filled sage action color (Button variant="secondary") |
--secondary-border |
2px ring around filled sage controls (Toolbar overrides it) |
--secondary-soft |
Lighter sage for icon rests and dividers (ViewToggle) |
--outline |
Outline button border |
--outline-hover |
Outline button border while hovered (over the primary fill) |
--toolbar |
Toolbar background |
--toolbar-foreground |
Toolbar text |
--toolbar-border |
Ring for filled controls sitting on the toolbar |
Typography
The theme ships Figtree (sans) and Spectral (serif). h1 is set in Spectral 500 italic (2.5rem / 2rem); h2-h6 are Figtree 600.
The scale is applied twice on purpose. theme-styles/base.css sets it inside @layer classic-theme.base, and the Tailwind preset emits the same rules through addBase. The second copy matters in any app that runs @tailwind base: preflight's h1..h6 { font-size: inherit; font-weight: inherit } is unlayered, so it outranks the layered theme rule (@csstools/postcss-cascade-layers preserves that ordering with specificity boosts). Without the preset's copy, bare headings render at body size. The text-h1 … text-h6 utilities carry the same size / line-height / weight when you need the scale on another element.
Customize the families:
:root {
--font-sans: 'Inter', system-ui, sans-serif;
--font-serif: 'Georgia', serif;
--font-mono: 'Fira Code', monospace;
}Spacing and Sizing
Adjust the border radius scale:
:root {
--radius: 0.5rem; /* Base radius */
}Components use this base value with modifiers:
rounded-sm=calc(var(--radius) - 0.25rem)rounded-md=var(--radius)rounded-lg=calc(var(--radius) + 0.25rem)
Using in Components
Access theme values in your components with Tailwind utilities:
<div class="bg-background text-foreground">
<h1 class="text-primary">Themed Heading</h1>
<p class="text-muted-foreground">Muted text</p>
<button class="bg-primary text-primary-foreground"> Primary Button </button>
</div>Or use CSS variables directly:
<style>
.custom-element {
background-color: hsl(var(--primary));
color: hsl(var(--primary-foreground));
}
</style>Brand Customization Example
Here's a complete example customizing the theme for a brand:
:root {
/* Custom brand colors */
--primary: 142 76% 36%; /* Green primary */
--primary-foreground: 0 0% 100%;
--secondary: 142 76% 96%; /* Light green */
--secondary-foreground: 142 76% 20%;
--accent: 38 92% 50%; /* Orange accent */
--accent-foreground: 0 0% 100%;
/* Custom radius for softer look */
--radius: 0.75rem;
}Next Steps
- Browse Components to see theming in action
- Learn about Form Patterns for consistent form styling
- Check out Accessibility for color contrast guidelines