Theming
How Thanawi tokens are layered, named, switched between modes, and exposed to Tailwind.
Token layers
Tokens come in three layers. Each layer may only reference the layer before it. Components use semantic tokens only. They never use primitives or raw values.
- 1
Primitives
The raw palette and scales. Context-free values in OKLCH.
--th-teal-600 - 2
Semantics
Named by role. Values change per mode; names never do.
--th-surface-primary - 3
Component usage
Components consume semantic tokens through Tailwind utilities.
bg-surface-primary
Naming
Every token has the --th- prefix. Semantic color tokens follow --th-<group>-<role>[-<state>]:
- surface: backgrounds, from the page canvas (
base) to filled controls (primary,negative). - content: text and icons. Use the
on-*roles for content that sits on a filled surface. - border: dividers, outlines and the focus ring (
focus).
Non-color tokens follow the same idea: --th-spacing-*, --th-font-size-*, --th-radius-*, --th-shadow-*, --th-duration-*, --th-ease-* and --th-z-*.
Modes
Light is the default and lives on :root. Dark mode is turned on with data-th-mode on any element, usually <html>. Every semantic name stays the same between modes; only the values change.
<html data-th-mode="dark">
…
<!-- a subtree can opt back into light -->
<section data-th-mode="light">…</section>
</html>The mode toggle in this site's header sets data-th-mode on <html> and remembers your choice.
Color format
OKLCH is the source of truth. Browsers with wide-gamut displays get P3-enhanced values, and browsers without oklch() get an sRGB hex fallback, which is declared first:
:root {
--th-surface-primary: #017167;
}
@supports (color: oklch(0 0 0)) {
:root {
--th-surface-primary: oklch(0.493 0.087 184.2);
}
}
@media (color-gamut: p3) {
:root {
--th-surface-primary: oklch(0.493 0.105 184.2); /* illustrative P3 value */
}
}Semantic colors
Every swatch below is painted from the live CSS variable, so it follows the mode toggle. Click a swatch to copy its var().
Surface
Content
Border
Tailwind bridge
@thanawi/tokens/tailwind.css maps tokens to Tailwind v4 theme variables with @theme inline. Utilities resolve to var(--th-*), so mode switching works without rebuilding.
| Utility | Resolves to |
|---|---|
bg-surface-base | var(--th-surface-base) |
text-content-muted | var(--th-content-muted) |
border-border-subtle | var(--th-border-subtle) |
ring-border-focus | var(--th-border-focus) |
rounded-md | var(--th-radius-md) |
shadow-sm | var(--th-shadow-sm) |
font-sans | var(--th-font-family-sans) |
dark: | [data-th-mode="dark"] subtree |
Radius
--th-radius-none--th-radius-xs--th-radius-sm--th-radius-md--th-radius-lg--th-radius-xl--th-radius-2xl--th-radius-fullShadow
--th-shadow-none--th-shadow-xs--th-shadow-sm--th-shadow-md--th-shadow-lg--th-shadow-xl