Docs
Color system
You've received a design from Pieter de Kroon. This explains how the color system is structured, so you can implement it correctly and extend it where needed.
Basics
The color system is built in two layers: brand tokens and component tokens. This separation keeps the system flexible — you swap the brand layer per project without touching a single component.
Brand tokens
Brand tokens are the raw color palette. They define every color available in the system as a numbered scale per color role: primary, secondary, neutral, danger, success, warning, and info.
Each scale runs from 50 (lightest) to 900 (darkest), with a 500-50 variant for 50% opacity where needed. The neutral scale is the exception, it runs from 1 (white) to 13 (near black), giving more granular control over surfaces, borders, and text.
Component tokens
Component tokens sit on top of the brand tokens. They translate raw color values into specific UI roles: what color does a primary button use on hover? What's the border color of an error input?
Each token is named after its context, not its color value:
This means components never reference brand tokens directly. A button doesn't know it's purple — it knows it's a primary button. That distinction is what makes the brand layer swappable.
Dark mode
Dark mode is handled entirely at the component token level. The brand token values stay the same, only the component token mappings change.
In dark mode, lighter neutrals flip to darker ones, and color accents shift one or two steps lighter to maintain contrast:
Implementation
Add both the brand tokens and component tokens to your global stylesheet, inside :root. Brand tokens first, component tokens second, component tokens reference brand tokens, so order matters.
Optional: Darkmode
For dark mode, add a second block scoped to a .dark class on the <html> or <body> element. You only need to override the component tokens here — the brand tokens stay the same.
Toggle the .dark class via JavaScript based on user preference or system setting: