Skip to content

Token Taxonomy

Six token families, one decision tree

Silvery ships six distinct token categories. Each has a different contract — picking the right one makes your UI adapt correctly across 84 schemes, four tiers, and every user's terminal. Picking the wrong one produces hardcoded-looking apps that don't respect user themes.

The decision tree, memorized:

  1. Want app identity?$brand
  2. Want a color for a tag / category / chart series / priority?$red, $blue, $green, … (one of 8)
  3. Want to signal state or validation?$error, $success, $warning, $info
  4. Want UI chrome (background, border, text)?$fg, $bg, $muted, $border, $primary, $accent, …
  5. Writing a syntax highlighter?$color0$color15
  6. Emphasizing something hierarchically? → typography preset (<H1>, <Small>, etc.)

Each branch below explains when it's the right answer.

1. App identity — $brand

The one color that's you. Your logo, your chrome, the signature accent that says "this is my app."

tsx
<Text color="$brand">MyApp v2.3</Text>
<Box borderColor="$brand">…</Box>
TokenResolves to
$brandApp's primary identity color. Defaults to scheme.primary (often the cursor color or the scheme's declared primary). Apps pin via <ThemeProvider tokens={{ brand: "#5B8DEF" }}>.
$brand-hover+0.04 L in OKLCH (+darken on light themes). For interactive hover states.
$brand-active+0.08 L in OKLCH. For active/pressed states.

Apple analogue: UIColor.tintColor / the per-app accent. Each app has ONE.

Don't use for: categorical tagging (use $red etc), semantic state (use $error etc), or body text (use $fg).

2. Categorical color ring — $red, $orange, $yellow, $green, $teal, $blue, $purple, $pink

Eight harmonious hues for tagging. Contrast-adjusted per scheme; visually balanced so no single hue pops more than another. These look great regardless of whether the user is in Dracula or Solarized.

tsx
// Tags
<Text color="$red">urgent</Text>
<Text color="$blue">research</Text>
<Text color="$green">done</Text>

// Calendar categories
<CalendarEvent color="$purple" title="Code review" />

// Chart series
<Series data={cpu} color="$teal" />
<Series data={mem} color="$orange" />
TokenResolves to
$redScheme's red, contrast-adjusted.
$orangeBlend of scheme's red + yellow.
$yellowScheme's yellow.
$greenScheme's green.
$tealBlend of scheme's green + cyan.
$blueScheme's blue (bright on dark themes).
$purpleScheme's magenta.
$pinkBlend of scheme's magenta + red.

Prior art: Apple's .systemRed/.systemIndigo/.systemTeal/…, Tailwind's bg-red-500, Material's red.500.

Don't use for: state semantics (use $error). Don't hardcode tag colors in your app config — let the theme pick.

Why not use $color1 etc? $color0..$color15 are raw ANSI slots (user's terminal exactly). $red is contrast-adjusted so it's readable on every scheme. Use raw colors only for syntax highlighters where exact terminal parity matters.

3. Semantic state — $error, $success, $warning, $info

Colors that communicate meaning. The reader parses "yellow = caution" because the token says so semantically, not because the hue happens to be warning-shaped.

tsx
<Text color="$error">Build failed</Text>
<Text color="$success">Deployed</Text>
<Text color="$warning">Deprecated API</Text>
<Text color="$info">3 updates available</Text>
TokenPaired bgPaired fg-on
$error$errorfg / $fg-on-errordanger, validation errors
$warning$warningfg / $fg-on-warningcaution, deprecations
$success$successfg / $fg-on-successcompletions, confirmations
$info$infofg / $fg-on-infoneutral info, tips

When an app needs a red that's NOT an error (e.g. "delete button" or a red tag category): use $red or $brand. $error is reserved for error state.

Visual state cue chain: don't rely on color alone. Pair with icons / attrs / text prefixes so colorblind users and monochrome terminals still convey state. See the Color Fundamentals tier degradation section.

4. UI chrome — $fg, $bg, $primary, $accent, $muted, $border, and friends

The design-system scaffolding. Most component code uses these. If a token isn't in one of the other categories, it's here.

Root + text hierarchy

TokenMeaning
$fgDefault body text
$bgDefault background
$muted / $fg-mutedSecondary text (captions, hints)
$faint / $fg-faintFine print (via <Small>)
$disabledfg / $fg-disabledInactive text
$inverse / $fg-inverseInverse text (on dark status bars over light themes, etc.)

Surface pairs

Every "surface" (background plane) comes as a bg-* + matching fg token. Pair them.

tsx
<Box backgroundColor="$surfacebg">
  <Text color="$surface">Card content</Text>
</Box>
Surface pairWhen
$bg / $fgDefault root
$surface / $surfacebgElevated cards
$popover / $popoverbgFloating menus, tooltips
$inverse / $inversebgStatus bars, footers
$muted / $mutedbgInline muted chips

Accent + primary / secondary

TokenMeaning
$primaryDesign-system primary (often the scheme's primary — not app brand). Use for: headings, focus indicators, nav highlights.
$secondaryDesign-system secondary.
$accentComplement of primary — the pop-out color.

Wait, $primary vs $brand? $primary is the scheme's primary color (Nord yellow, Dracula purple, etc). $brand is the app's identity. Apps that want their brand to dominate pin $brand; apps that want to blend in let $brand default to $primary.

TokenMeaning
$borderDefault structural border — faint, not prominent (1.5:1 contrast target).
$inputborder / $border-inputInput field border (3:1 WCAG 1.4.11).
$focusborder / $border-focusFocused input border (usually primary/link).
$linkHyperlink color.

Selection + cursor

TokenMeaning
$selection / $selectionbgMulti-row selection highlight (e.g. marquee, visual mode).
$cursor / $cursorbgSingle-point cursor highlight — matches the user's terminal cursor color.

5. Raw ANSI palette — $color0$color15

The user's terminal colors, verbatim. No contrast adjustment, no theming. What the user configured in their emulator is what you get.

tsx
<Text color="$color1">red</Text>  {/* scheme.red directly */}
<Text color="$color14">cyan bright</Text>  {/* scheme.brightCyan directly */}
IndexSlot
0black
1red
2green
3yellow
4blue
5magenta
6cyan
7white
8–15bright variants of the above

Use for: syntax highlighters (Prettier/tree-sitter-style) where exact terminal color parity matters. Git diff viewers. Anywhere the app explicitly wants the user's ANSI verbatim.

Don't use for: everyday UI. $red / $blue / $green are always preferable — they're contrast-adjusted, they don't look muddy on themes where the raw ANSI red is a subtle brown.

6. Typography presets — <H1>, <H2>, <H3>, <Muted>, <Small>, <Strong>, <Em>, <Code>, <Blockquote>

Not tokens per se, but the hierarchy primitives. Each preset bundles color + attrs so you don't hand-write <Text color="$primary" bold>.

tsx
<H1>Page title</H1>
<H2>Section</H2>
<H3>Group</H3>
<Muted>Caption text</Muted>
<Small>Fine print</Small>
<Strong>Emphasis</Strong>
<Em>Italic emphasis</Em>
<Code>inline code</Code>
<Blockquote>pull quote</Blockquote>

Under the hood: these resolve to <Text color="$primary" bold> etc. When theme-system-v2 variants ship, you'll also be able to write <Text variant="h1"> — same result.

Decision tree, visualized

What color are you choosing for?

├── The app's identity / logo / signature chrome → $brand (+ -hover/-active)

├── A tag / category / chart series / priority level (no state meaning)
│    → $red / $orange / $yellow / $green / $teal / $blue / $purple / $pink

├── Communicating STATE (error, warning, success, info)
│    → $error / $warning / $success / $info

├── UI chrome (text, bg, borders, surfaces)
│    → $fg / $bg / $muted / $border / $primary / $accent / $surface-bg / …

├── Hierarchy (heading, fine print, emphasis)
│    → <H1>, <Small>, <Strong>, <Muted>, <Em>, <Code>, <Blockquote>

└── Raw terminal ANSI (syntax highlighter, user-exact parity)
     → $color0..$color15

Anti-patterns

  • $error for anything that isn't literally an error — e.g. "delete" buttons, red tags. Use $red or $brand instead.
  • $color1 for everyday UI — it's the user's raw ANSI, not contrast-adjusted. Use $red unless you're writing a syntax highlighter.
  • $primary for app brand$primary is the scheme's primary. For app brand, use $brand.
  • Hardcoded hex for a tinted surface — use $surface-bg / $popover-bg or mix($bg, $token, N%).
  • dim or dimColor anywheredim is a rendering detail. Use $muted, <Small>, or $disabledfg instead. (See the Styling Guide for the full deprecation rationale.)

Defining your own tokens

If you need a token that isn't covered above — priority levels, calendar-specific accents, brand sub-colors — use defineTokens():

tsx
import { defineTokens } from "silvery/theme"

const appTokens = defineTokens({
  "$priority-p0": { derive: (s) => s.brightRed },   // derivation — adapts to scheme
  "$priority-p1": { derive: (_, t) => t.red },
  "$priority-p2": { derive: (_, t) => t.orange },
  "$my-brand": { rgb: "#5B8DEF", ansi16: "brightBlue" },  // fixed brand
})

<ThemeProvider tokens={appTokens}>
  <App />
</ThemeProvider>

See the Custom Tokens guide for the full API.

See also