Tokens
Every variable the library reads: colour, radius, shadow, typography, spacing and z-index.
Colour
31 variables, declared per palette and twice over — once for light, once for dark. Every name exists in all five palettes, so a component can rely on it being there.
| Variable | Utility | Role | |
|---|---|---|---|
background in light mode: oklch(0.985 0.004 255)background in dark mode: oklch(0.17 0.025 265) | --background | bg-background | The page. Nothing else uses it. |
foreground in light mode: oklch(0.21 0.03 265)foreground in dark mode: oklch(0.96 0.01 255) | --foreground | text-foreground | Body text and any icon at full weight.Sits on --background. |
card in light mode: oklch(1 0 0)card in dark mode: oklch(0.21 0.03 265) | --card | bg-card | A raised surface sitting on the background. |
card-foreground in light mode: oklch(0.21 0.03 265)card-foreground in dark mode: oklch(0.96 0.01 255) | --card-foreground | text-card-foreground | Text on a card.Sits on --card. |
popover in light mode: oklch(1 0 0)popover in dark mode: oklch(0.21 0.03 265) | --popover | bg-popover | Overlay surfaces — menus, dropdowns, tooltips. |
popover-foreground in light mode: oklch(0.21 0.03 265)popover-foreground in dark mode: oklch(0.96 0.01 255) | --popover-foreground | text-popover-foreground | Text in an overlay.Sits on --popover. |
border in light mode: oklch(0.90 0.015 255)border in dark mode: oklch(0.30 0.025 265) | --border | border-border | Every hairline and divider. |
input in light mode: oklch(0.90 0.015 255)input in dark mode: oklch(0.32 0.025 265) | --input | border-input | Field borders, so they can differ from dividers. |
reverse in light mode: oklch(0.21 0.03 265)reverse in dark mode: oklch(0.96 0.01 255) | --reverse | bg-reverse | Flips with the mode — the foreground colour, used as a fill. |
primary in light mode: oklch(0.55 0.20 258)primary in dark mode: oklch(0.62 0.19 258) | --primary | bg-primary | The one accent. Actions, active states. |
primary-foreground in light mode: oklch(0.99 0.01 255)primary-foreground in dark mode: oklch(0.99 0.01 255) | --primary-foreground | text-primary-foreground | Text on a primary fill — not the same as --foreground.Sits on --primary. |
secondary in light mode: oklch(0.96 0.012 255)secondary in dark mode: oklch(0.27 0.03 265) | --secondary | bg-secondary | A quieter fill for secondary actions. |
secondary-foreground in light mode: oklch(0.25 0.03 265)secondary-foreground in dark mode: oklch(0.96 0.01 255) | --secondary-foreground | text-secondary-foreground | Text on a secondary fill.Sits on --secondary. |
muted in light mode: oklch(0.96 0.01 255)muted in dark mode: oklch(0.25 0.03 265) | --muted | bg-muted | Recessed surfaces: toolbars, table stripes, wells. |
muted-foreground in light mode: oklch(0.52 0.03 258)muted-foreground in dark mode: oklch(0.70 0.03 258) | --muted-foreground | text-muted-foreground | Secondary text. The most-used colour in the library after --foreground.Sits on --background. |
accent in light mode: oklch(0.93 0.04 255)accent in dark mode: oklch(0.32 0.06 260) | --accent | bg-accent | Hover and highlight fills inside menus. |
accent-foreground in light mode: oklch(0.30 0.08 260)accent-foreground in dark mode: oklch(0.96 0.01 255) | --accent-foreground | text-accent-foreground | Text on an accent fill.Sits on --accent. |
ring in light mode: oklch(0.55 0.20 258)ring in dark mode: oklch(0.62 0.19 258) | --ring | ring-ring | The focus ring. Move it with --primary or focus looks broken. |
destructive in light mode: oklch(0.58 0.222 27)destructive in dark mode: oklch(0.62 0.21 25) | --destructive | bg-destructive | Delete, remove, irreversible. |
destructive-foreground in light mode: oklch(0.99 0.01 255)destructive-foreground in dark mode: oklch(0.99 0.01 255) | --destructive-foreground | text-destructive-foreground | Text on a destructive fill.Sits on --destructive. |
success in light mode: oklch(0.53 0.16 150)success in dark mode: oklch(0.53 0.16 150) | --success | bg-success | Confirmation. Also the check in a copy button. |
success-foreground in light mode: oklch(0.99 0.01 255)success-foreground in dark mode: oklch(0.99 0.01 255) | --success-foreground | text-success-foreground | Text on a success fill.Sits on --success. |
warning in light mode: oklch(0.78 0.15 75)warning in dark mode: oklch(0.74 0.15 75) | --warning | bg-warning | Needs attention but is not an error. |
warning-foreground in light mode: oklch(0.20 0.03 75)warning-foreground in dark mode: oklch(0.20 0.03 75) | --warning-foreground | text-warning-foreground | Text on a warning fill — dark, because warning fills are pale.Sits on --warning. |
info in light mode: oklch(0.54 0.16 240)info in dark mode: oklch(0.54 0.16 240) | --info | bg-info | Neutral notice. |
info-foreground in light mode: oklch(0.99 0.01 255)info-foreground in dark mode: oklch(0.99 0.01 255) | --info-foreground | text-info-foreground | Text on an info fill.Sits on --info. |
chart-1 in light mode: oklch(0.55 0.20 258)chart-1 in dark mode: oklch(0.62 0.19 258) | --chart-1 | text-chart-1 | First data series. Conventionally the brand colour. |
chart-2 in light mode: oklch(0.60 0.16 220)chart-2 in dark mode: oklch(0.66 0.16 220) | --chart-2 | text-chart-2 | Data series 2. |
chart-3 in light mode: oklch(0.65 0.14 280)chart-3 in dark mode: oklch(0.70 0.14 280) | --chart-3 | text-chart-3 | Data series 3. |
chart-4 in light mode: oklch(0.55 0.12 200)chart-4 in dark mode: oklch(0.60 0.12 200) | --chart-4 | text-chart-4 | Data series 4. |
chart-5 in light mode: oklch(0.50 0.18 300)chart-5 in dark mode: oklch(0.56 0.18 300) | --chart-5 | text-chart-5 | Data series 5. |
The two chips are the sapphire palette's light and dark values — the ones a fresh install renders in. Hover one for theoklch() behind it. Grouped by what they are for: surface (9), brand (9), state (8), chart (5).
Foreground pairs are not interchangeable
--primary-foreground is the text colour that survives on a primary fill, which is not the same as --foreground. Pairing a fill with the wrong foreground is the most common way a custom palette fails contrast — the theme generator measures every pair as you edit it.Radius
One value — 0.625rem — and the rest derived from it with calc(). Change the first and the whole library changes shape.
| Variable | Value | Utility |
|---|---|---|
| --radius | 0.625rem | The one value the rest derive from. |
| --radius-xs | calc(var(--radius) - 6px) | rounded-xs |
| --radius-sm | calc(var(--radius) - 4px) | rounded-sm |
| --radius-md | calc(var(--radius) - 2px) | rounded-md |
| --radius-lg | var(--radius) | rounded-lg |
| --radius-xl | calc(var(--radius) + 4px) | rounded-xl |
| --radius-2xl | calc(var(--radius) + 8px) | rounded-2xl |
Shadow
Elevation, with every alpha multiplied by one knob so the whole set can be flattened without touching a component.
| Variable | Value | Utility |
|---|---|---|
| --shadow-strength | 1 | Multiplies every alpha below. 0 removes all shadows. |
| --shadow-xs | 0 1px 2px 0 oklch(0 0 0 / calc(0.05 * var(--shadow-strength))) | shadow-xs |
| --shadow-sm | 0 1px 3px 0 oklch(0 0 0 / calc(0.10 * var(--shadow-strength))), 0 1px 2px -1px oklch(0 0 0 / calc(0.10 * var(--shadow-strength))) | shadow-sm |
| --shadow-md | 0 4px 6px -1px oklch(0 0 0 / calc(0.10 * var(--shadow-strength))), 0 2px 4px -2px oklch(0 0 0 / calc(0.10 * var(--shadow-strength))) | shadow-md |
| --shadow-lg | 0 10px 15px -3px oklch(0 0 0 / calc(0.10 * var(--shadow-strength))), 0 4px 6px -4px oklch(0 0 0 / calc(0.10 * var(--shadow-strength))) | shadow-lg |
| --shadow-xl | 0 20px 25px -5px oklch(0 0 0 / calc(0.10 * var(--shadow-strength))), 0 8px 10px -6px oklch(0 0 0 / calc(0.10 * var(--shadow-strength))) | shadow-xl |
| --shadow-2xl | 0 25px 50px -12px oklch(0 0 0 / calc(0.25 * var(--shadow-strength))) | shadow-2xl |
| --shadow-brand | 0 8px 24px -6px var(--primary) | A primary-tinted glow. Use sparingly. |
The steps are a ladder, not a palette — a component should move up it when it rises above the page, and nothing should skip from shadow-xs to shadow-2xl on hover.
Typography
Three stacks, each opening with a hook variable so an app can drop its own face in without restating the stack.
| Variable | Value | Utility |
|---|---|---|
| --font-sans | var(--kip-font-sans, ui-sans-serif), ui-sans-serif, system-ui, sans-serif | font-sans |
| --font-mono | var(--kip-font-mono, ui-monospace), ui-monospace, "SFMono-Regular", monospace | font-mono |
| --font-display | var(--kip-font-display, var(--kip-font-sans, ui-sans-serif)), ui-sans-serif, system-ui, sans-serif | font-display |
| --text-2xs | 0.6875rem | Below Tailwind's smallest step. |
| --text-2xs--line-height | 1rem | — |
| --tracking-tightest | -0.05em | Display headings. |
| --tracking-display | -0.02em | Large text that is not a heading. |
Set --kip-font-sans and everything follows. The fallback inside each var() is not decoration: an undefined custom property with no fallback invalidates the whole declaration, which would leave every component rendering in the browser's serif default.
Spacing and breakpoints
A 4px grid, two semantic steps for page layout, and two breakpoints added at the ends of Tailwind's range.
| Variable | Value | Use |
|---|---|---|
| --spacing | 0.25rem | The 4px base grid every step multiplies. |
| --spacing-gutter | 1.5rem | Horizontal page inset. |
| --spacing-section | 5rem | Vertical rhythm between sections. |
| --breakpoint-xs | 24rem | Below Tailwind's sm. |
| --breakpoint-3xl | 120rem | Above 2xl. |
Z-index
A named ladder in place of ad-hoc numbers, so two overlays can never argue about which is on top.
| Variable | Value | Utility |
|---|---|---|
| --z-base | 0 | z-base |
| --z-dropdown | 1000 | z-dropdown |
| --z-sticky | 1100 | z-sticky |
| --z-fixed | 1200 | z-fixed |
| --z-overlay | 1300 | z-overlay |
| --z-modal | 1400 | z-modal |
| --z-popover | 1500 | z-popover |
| --z-toast | 1600 | z-toast |
| --z-tooltip | 1700 | z-tooltip |
Tailwind v4 has no z-index theme namespace, so these are declared as @utility rules rather than generated. The order encodes the rule that matters: a tooltip opened from inside a modal has to sit above it.