Semantic vs raw color
A raw color token names the color itself: --blue-500, --gray-900. A semantic token names the job the color does: --primary, --background, --muted-foreground. Components can then ignore the brand's literal hues. A button styled with bg-primary text-primary-foreground works with sage green, hot pink, or a dark theme because the role stays fixed while its value changes.
This is the model shadcn/ui popularized and Tailwind's theming builds on. With semantic tokens, re-theming an app can be limited to one :root block. Hardcoded classes such as bg-gray-900 and text-white turn the same change into a codebase-wide search.
The foreground pairing rule
Most base roles come with a paired -foreground role for text or icons on that surface: --primary / --primary-foreground, --card / --card-foreground, --muted / --muted-foreground. Use --primary-foreground on --primary instead of hoping the default foreground has enough contrast. Each pair must still be checked in both modes.
The 28 roles a complete system needs
A minimal three-color palette leaves 25 decisions undefined: hover states, muted text, borders, focus rings, chart series, dark mode. A complete system names all of them. Identity Forge kits define these 28 roles, grouped by what they do, for light and dark:
- Surfaces:
background/foreground,card/card-foreground,popover/popover-foreground. The page, raised panels, and floating layers, each with its legible text color. - Brand & emphasis:
primary/primary-foreground,secondary/secondary-foreground,accent/accent-foreground. The main action, the supporting one, and the highlight. - Quiet & neutral:
muted/muted-foreground. Subdued backgrounds and secondary text. - State:
destructive/destructive-foreground,success/success-foreground,warning/warning-foreground. Errors, confirmations, and cautions. - Form & focus:
border,input,ring. Dividers and outlines, form field surfaces, and the focus indicator. - Data:
chart-1,chart-2,chart-3,chart-4,chart-5. Five distinct, on-brand series colors so charts don't fall back to a generic default palette.
Why five chart colors matter
Data visualization is where under-specified systems break most visibly: a dashboard with three brand colors and a random rainbow for its bar chart. Defining chart-1…5 up front keeps graphs inside the same visual language as the rest of the app.
See the roles on a real kit
Below is the free ambient-sage kit rendered entirely from these tokens. The swatch row is --primary, --secondary, --accent, and the five chart roles; the button uses --primary with --primary-foreground; the surfaces use --background, --card, and --muted. Nothing here is a hardcoded color:
After Work Chill
Double tap on a widget to edit settings
Plus Jakarta Sans · 28 semantic tokens · light + dark
Get a full token set
You can define all 28 roles by hand, but it's tedious to keep light and dark balanced and accessible. Every Identity Forge kit ships them complete in both modes, exportable as CSS variables, Tailwind v3/v4 @theme, a shadcn registry item, or DTCG/W3C JSON. The quickest way to drop a complete set into a shadcn/ui project:
npx shadcn add https://identityforge.io/r/ambient-sage.jsonThe tokens are also half of a DESIGN.md: the values the written brief references. Together they're what you give a coding agent so its UI stays coherent.
FAQ
What are semantic color tokens?
Color variables named by role rather than hue: `--primary`, `--background`, `--muted-foreground` instead of `--blue-500`. Components style against the role name, so changing themes or switching to dark mode never requires editing components.
How many color tokens does a design system need?
Identity Forge uses 28 semantic roles: surfaces with their foregrounds, brand and muted roles, state colors, form roles, and five chart colors. Every role has a light and dark value.
What is the -foreground convention?
Most base roles pair with a `-foreground` role for the text or icons placed on that surface: `--primary` with `--primary-foreground`. The pairing guarantees legible contrast in both light and dark without guesswork.
How do I export a full semantic token set?
Every Identity Forge kit exports its 28 roles (light + dark) as CSS variables, Tailwind v3/v4 @theme, a shadcn registry item, or DTCG/W3C JSON. For shadcn/ui, `npx shadcn add https://identityforge.io/r/<slug>.json` installs them directly.