Skip to content

Theming

Every color in the system comes from a CSS variable token. To restyle the components, you override tokens — no component code, no overrides, no specificity battles.

There are two layers:

  • Semantic tokens — role-based (--color-bg-surface, --color-text-primary). This is the layer you theme. Each maps a role to a color.
  • Primitives — the raw palette (--color-bg-200, --color-text-900) that the semantic tokens reference. Internal; you rarely touch these directly.

Think of it like shadcn: you set the semantic roles, not the raw colors.

How to theme

Override the semantic tokens after importing the library's tokens. Set them to any color you like — a literal value or one of your own variables:

css
@import "tailwindcss";
@import "@dlbcodes/my-design-system/tokens.css";

:root {
    --color-bg-base: oklch(99% 0 0);
    --color-bg-surface: oklch(97% 0 0);
    --color-text-primary: oklch(20% 0.02 260);
    --color-border-default: oklch(90% 0.01 260);
}

Because every component reads these roles, overriding them re-themes the whole system at once. Override only the tokens you want to change — the rest keep their defaults.

Semantic tokens

These are the tokens to override.

Text

TokenRole
--color-text-primaryBody copy, headings
--color-text-secondaryLabels, metadata
--color-text-tertiaryPlaceholders, hints
--color-text-disabledDisabled state
--color-text-inverseText on dark surfaces

Background

TokenRole
--color-bg-basePage background
--color-bg-surfaceCards, panels
--color-bg-raisedFloating / selected surface
--color-bg-elevatedDropdowns, tooltips
--color-bg-subtleHover states, tags
--color-bg-strongSeparators, badges
--color-bg-inverseDark surfaces, banners

Border

TokenRole
--color-border-subtleSoft dividers
--color-border-defaultInputs, cards
--color-border-strongFocus, emphasis
--color-border-darkStrong outline

Status

Each status has a surface, border, and text token:

StatusSurfaceBorderText
Success--color-success-surface--color-success-border--color-success-text
Warning--color-warning-surface--color-warning-border--color-warning-text
Info--color-info-surface--color-info-border--color-info-text
Danger--color-danger-surface--color-danger-border--color-danger-text

Going further: primitives

Semantic tokens reference an internal palette of primitives — neutral ramps (--color-text-100…900, --color-bg-0…900), brand, accent, and per-status scales. You generally don't need these, but if you want to shift the underlying palette (so every semantic role that uses a primitive moves together), you can override a primitive instead:

css
:root {
    /* shift the whole neutral text scale's darkest step */
    --color-text-900: oklch(15% 0.01 260);
}

Most of the time, overriding semantic tokens is the right tool — reach for primitives only when you want a broad palette shift.

Utilities

The token file also ships two scrollbar utilities you can use on any element:

  • no-scrollbar — hides the scrollbar while keeping scroll behavior.
  • scrollbar-thin — a slim, themed scrollbar.
vue
<div class="overflow-y-auto scrollbar-thin">…</div>