Skip to content

Design system

Documentation

DesignFoundations / Colors

Foundations / Colors

Stable

Colors

A complete 50–950 palette gives product teams enough range to express hierarchy, while semantic roles keep those choices consistent across light and dark themes.

On this page

The source of truth is packages/ui/src/styles/tokens.css. Primitive OKLCH scales feed semantic roles; the existing names such as --background, --foreground, and --primary remain compatibility aliases while the system evolves. The :root roles describe light mode and the .dark block overrides the same roles for dark mode.

There are twelve chromatic families — red, orange, amber, yellow, lime, green, teal, cyan, blue, indigo, violet, and pink — plus the neutral foundation. Every chromatic family has eleven predictable steps: 50, 100 through 900, and 950. Each chip includes the token name and a copy action; the scales stack vertically and reflow into one column on narrow screens so no value is clipped.

Raw palette

Raw values are building material, not a component API. Use them to define a new semantic role or a documented illustration; product markup should prefer a semantic role or the colorPalette prop.

Neutral

--color-neutral-*

11 steps
50--color-neutral-50
100--color-neutral-100
200--color-neutral-200
300--color-neutral-300
400--color-neutral-400
500--color-neutral-500
600--color-neutral-600
700--color-neutral-700
800--color-neutral-800
900--color-neutral-900
950--color-neutral-950

Red

--color-red-*

11 steps
50--color-red-50
100--color-red-100
200--color-red-200
300--color-red-300
400--color-red-400
500--color-red-500
600--color-red-600
700--color-red-700
800--color-red-800
900--color-red-900
950--color-red-950

Orange

--color-orange-*

11 steps
50--color-orange-50
100--color-orange-100
200--color-orange-200
300--color-orange-300
400--color-orange-400
500--color-orange-500
600--color-orange-600
700--color-orange-700
800--color-orange-800
900--color-orange-900
950--color-orange-950

Amber

--color-amber-*

11 steps
50--color-amber-50
100--color-amber-100
200--color-amber-200
300--color-amber-300
400--color-amber-400
500--color-amber-500
600--color-amber-600
700--color-amber-700
800--color-amber-800
900--color-amber-900
950--color-amber-950

Yellow

--color-yellow-*

11 steps
50--color-yellow-50
100--color-yellow-100
200--color-yellow-200
300--color-yellow-300
400--color-yellow-400
500--color-yellow-500
600--color-yellow-600
700--color-yellow-700
800--color-yellow-800
900--color-yellow-900
950--color-yellow-950

Lime

--color-lime-*

11 steps
50--color-lime-50
100--color-lime-100
200--color-lime-200
300--color-lime-300
400--color-lime-400
500--color-lime-500
600--color-lime-600
700--color-lime-700
800--color-lime-800
900--color-lime-900
950--color-lime-950

Green

--color-green-*

11 steps
50--color-green-50
100--color-green-100
200--color-green-200
300--color-green-300
400--color-green-400
500--color-green-500
600--color-green-600
700--color-green-700
800--color-green-800
900--color-green-900
950--color-green-950

Teal

--color-teal-*

11 steps
50--color-teal-50
100--color-teal-100
200--color-teal-200
300--color-teal-300
400--color-teal-400
500--color-teal-500
600--color-teal-600
700--color-teal-700
800--color-teal-800
900--color-teal-900
950--color-teal-950

Cyan

--color-cyan-*

11 steps
50--color-cyan-50
100--color-cyan-100
200--color-cyan-200
300--color-cyan-300
400--color-cyan-400
500--color-cyan-500
600--color-cyan-600
700--color-cyan-700
800--color-cyan-800
900--color-cyan-900
950--color-cyan-950

Blue

--color-blue-*

11 steps
50--color-blue-50
100--color-blue-100
200--color-blue-200
300--color-blue-300
400--color-blue-400
500--color-blue-500
600--color-blue-600
700--color-blue-700
800--color-blue-800
900--color-blue-900
950--color-blue-950

Indigo

--color-indigo-*

11 steps
50--color-indigo-50
100--color-indigo-100
200--color-indigo-200
300--color-indigo-300
400--color-indigo-400
500--color-indigo-500
600--color-indigo-600
700--color-indigo-700
800--color-indigo-800
900--color-indigo-900
950--color-indigo-950

Violet

--color-violet-*

11 steps
50--color-violet-50
100--color-violet-100
200--color-violet-200
300--color-violet-300
400--color-violet-400
500--color-violet-500
600--color-violet-600
700--color-violet-700
800--color-violet-800
900--color-violet-900
950--color-violet-950

Pink

--color-pink-*

11 steps
50--color-pink-50
100--color-pink-100
200--color-pink-200
300--color-pink-300
400--color-pink-400
500--color-pink-500
600--color-pink-600
700--color-pink-700
800--color-pink-800
900--color-pink-900
950--color-pink-950

Semantic palette

Semantic roles describe what a color does, not which hue it happens to use. They are the stable contract for surfaces, text, actions, and status feedback.

RoleTokenPair withUse for
Page--color-bg-page--color-text-primaryApplication canvas and document background.
Surface--color-bg-surface--color-text-primaryCards and contained content.
Elevated--color-bg-elevated--color-text-primaryPopovers and content above a surface.
Subtle--color-bg-subtle--color-text-secondaryQuiet controls, hover states, and code context.
Code--color-bg-code--color-text-primaryReadable code blocks in both themes without a literal black mix.
Backdrop--color-backdropForeground contentSeparates modal content without coupling Dialog to a literal color.
Primary text--color-text-primaryAny background roleHeadings, labels, and essential body copy.
Secondary text--color-text-secondaryAny background roleSupporting copy; never the only way to identify an action.
Primary action--color-action-primary--color-text-on-brandOne clear action or link emphasis.
Border--color-border-defaultSurface roleDividers, fields, and component boundaries.
Scrollbar thumb--color-scrollbar-thumb--color-scrollbar-trackQuiet draggable handle revealed for bounded regions during interaction.
Scrollbar interaction--color-scrollbar-thumb-hover / --color-scrollbar-thumb-active--color-scrollbar-trackClarifies the handle during hover, focus, or drag without a permanent rail.

Light and dark roles

Semantic status roles intentionally change their effective shade between themes. The same component API remains readable without adding a light/dark branch in product code.

RoleLight surfaceDark surfaceMeaning
successgreen-50 / green-800green-900 / green-300Completed or safe result.
warningamber-50 / amber-800amber-900 / amber-300Needs attention without blocking.
dangerred-50 / red-800red-900 / red-300Risk, invalid input, or destructive intent.
infoblue-50 / blue-800blue-900 / blue-300Helpful context that is not a state change.
colorPaletteSolid, soft, and outline rolesThe same roles against dark surfacesExplicit hue choice for Button and Badge without raw values in markup.

Interaction states

Success

Completed or safe result. Pair with a short message, not color alone.

Warning

Needs attention but does not block the task.

Danger

Risk, invalid input, or destructive intent. Confirm irreversible actions.

Info

Helpful context that is not a success, warning, or error.

Using color

Start with the surface role, then choose the text role that belongs to it. Use --color-action-primary for an action or link, not as a decorative accent that competes with the action hierarchy. For a deliberate hue on a Button or Badge, use colorPalette="red" (or another supported family) and keep the component's existing variant.

Semantic Badge variants (success, warning, danger, and info) keep their fixed meaning even if a colorPalette value is passed. Button's destructive variant likewise remains danger red; custom palettes apply to its other variants.

Do

Pair --color-bg-surface with --color-text-primary, then add a border or icon when status matters.

Do not

Use a raw violet or red value directly in markup, or make color the only signal for an error.

Check both canvases at normal text size and in keyboard focus states before shipping. Corner geometry lives on the Border & Radius page; color should not be used to compensate for an unclear surface hierarchy.