v1.0

Colors

88 semantic color tokens. One class per role, almost no dark-mode overrides.

Create UI ships a single color system built on semantic tokens. Instead of reaching for a raw color like red-600 and remembering to add a dark-mode override, you name the role a color plays (bg-error-base, text-body, border-primary-weak) and the system resolves the right value for the active theme.

There are 88 of them: ten five-step ramp families plus the static, background, text, overlay, and shadow groups. Across the whole component library only two files still need a dark: color override. Colors are the one foundation that does not scale with the viewport: they move on the light and dark axis instead.

The same markup, in both themes:

Light
Team plan

Invite your team

Everyone you add gets the same seat, billed once per member.

Dark
Team plan

Invite your team

Everyone you add gets the same seat, billed once per member.

bg-statictext-strongesttext-bodyborder-lightbg-primary-base

Not one dark: in this markup.

Why semantic tokens

The same surface, written two ways:

// Raw colors: you hand-manage every theme and every state.
<div className="bg-red-600 text-white dark:bg-red-500 dark:text-neutral-50" />
 
// Semantic tokens: name the intent, theming is handled for you.
<div className="bg-error-base text-white" />

The payoff:

  • Intent over value. bg-error-base says what it is. bg-red-600 makes the next reader guess.
  • Dark mode for free. Each token already carries a light and a dark value. You almost never write a dark: color override again.
  • One place to retheme. Change a token mapping once and every component that uses it updates. The brand primary family is just an alias you can repoint.

The strength ramp

Most families share one vocabulary, ordered from lightest to most prominent:

weakest → weak → base → strong → strongest
  • weakest / weak: tinted backgrounds and subtle fills.
  • base: the solid, default color (buttons, icons, indicators).
  • strong / strongest: text, emphasis, and high-contrast detail on top of the weak fills.

Every swatch below is split on the diagonal: the light value fills the top-left, the dark value the bottom-right, with both hex values printed underneath. The step name under each swatch copies the token.

L #EEF2FFD #615FFF29
L #E0E7FFD #615FFF3D
L #4F39F6D #615FFF
L #432DD7D #7C86FF
L #312C85D #C6D2FF

primary is an alias, so a theme can repoint the whole family to any hue without touching a single component.

Background and text

Neutral surfaces use a longer ramp built for layering, resolved from a zinc base for a refined, slightly cool gray. Lower steps are page and card backgrounds; higher steps are borders, dividers, and strong UI chrome. The ramp inverts in dark mode, which the split swatches show directly: weakest is the lightest surface in light mode and the darkest in dark.

L #FAFAFAD #18181B
L #F4F4F5D #27272A
L #E4E4E7D #3F3F46
L #D4D4D8D #71717B
L #3F3F46D #D4D4D8
L #27272AD #E4E4E7
L #09090BD #FAFAFA

Text has its own roles. strongest is for headings and high-emphasis copy, body for comfortable reading, and placeholder / disabled for de-emphasized states. A text token is only ever as good as its legibility, so these are shown as real type rather than as fills:

Light
Headings and high-emphasis copy
Comfortable reading for running text.
Optional, hints and empty fields.
Unavailable, not interactive.
Dark
Headings and high-emphasis copy
Comfortable reading for running text.
Optional, hints and empty fields.
Unavailable, not interactive.

Status and brand families

Every family carries the same weakest → strongest ramp and is meant for one kind of meaning. Reach for the family that matches intent, not the one that happens to be the right hue. On a shared baseline the families compare directly, which is the question you actually have when choosing between warning and error.

familiesSame ramp, same order, one baselineweakest → strongest
Brand and primary actions
Destructive actions, failures, invalid input
Confirmations and completed states
Non-blocking cautions
Neutral, informational messaging
Verified badges and trust marks
Feature callouts
Highlighted promotions
Away presence
Stable or neutral status

The first is brand. The next four carry status. The last five are accents for product-specific meaning: a verified badge, a feature callout, a highlighted promotion, an away presence dot, a stable or neutral state.

Static colors

Static tokens are theme-aware foreground anchors for sitting on top of colored or inverted surfaces. static-white is white in light mode and flips to black in dark mode. static-black does the opposite. That flip is what keeps text legible on an inverted surface, since the surface itself changes with the theme.

Light
text-static on an inverted surface
text-white on a brand fill
Dark
text-static on an inverted surface
text-white on a brand fill

Each static color also exposes alpha-* steps (static-white-alpha-16, static-black-alpha-24, ...) for translucent overlays such as spinner tracks and hairlines on top of color. They appear over a checkerboard in the token reference below so the transparency itself reads.

Overlay and interaction

These tokens are alpha tints used for state and depth, not solid fills.

  • scrim / scrim-strong: dimming behind modals, drawers, and popovers.
  • hover / active: subtle wash for interactive states on the default surface, in either theme.
  • hover-inverted / active-inverted: the same idea for a surface that is inverted relative to the active theme.

Each one is subtle by design, so scrim and hover are shown next to the untouched surface. The rest of the set behaves the same way, one step stronger or inverted:

Light
rest
Dialog title
bg-scrim, with a panel above it
Table row
rest
Table row
bg-hover
Dark
rest
Dialog title
bg-scrim, with a panel above it
Table row
rest
Table row
bg-hover
// Dialog backdrop
<div className="bg-scrim" />
 
// Row hover on the default surface
<button className="hover:bg-hover active:bg-active" />

Guidelines

// Do
<div className="bg-error-base text-white" />
 
// Avoid: raw color, manual theme handling, no shared meaning
<div className="bg-red-600 text-white dark:bg-red-500" />
  • Use base for solid fills, weakest / weak for tinted backgrounds, strong / strongest for text and emphasis.
  • Reserve raw primitive scales (bg-red-600) for the rare case a design genuinely needs a one-off hue with no semantic role.
  • Let the root .dark class do the work. If you find yourself writing dark:bg-* for color, there is almost always a token that already handles it.

Token reference

Every semantic token with the hex it resolves to in each theme. Search matches both the name and the value, so pasting a hex finds the token that paints it. Press / to jump to the search field, and click any swatch to copy its token name.

88 of 88
Static
Background
Text
Primary
Error
Success
Warning
Info
Verified
Feature
Highlighted
Away
Stable
Overlay
Shadow

How it works

Every token lands in your globals.css when you set up Create UI.

A token flows through three layers before it reaches your markup.

1. Primitive scales. The raw palette: zinc, red, blue, indigo, and the rest, each with shades 50-950 plus alpha-* steps, alongside bare black and white that carry only alpha-* steps. They arrive as --color-* variables and are rarely used directly in product code. Two families are aliases a theme repoints: primary resolves to indigo, and neutral resolves to zinc.

2. Semantic tokens. Each maps a role to a light and a dark primitive, and remaps under .dark:

globals.css
:root {
  --color-primary-base: var(--color-primary-600);
}
.dark {
  --color-primary-base: var(--color-primary-500);
}

3. Tailwind utilities. An @theme block re-exports each variable so the token becomes an ordinary color utility:

globals.css
@theme inline {
  --color-primary-base: var(--color-primary-base);
}

Dark mode is driven by a .dark class on an ancestor (usually <html>). Everything inside it resolves the dark value automatically, so you set the theme once at the root and never thread it through components.

Every one of these tokens ships with the components.Install Create UI