Skip to content

Semantic Tokens & Typography

@theme-kit/core — the token system

Theme Kit isn't another dark-mode library. Every theme is a complete design system — colors, typography, spacing, radius, shadows, border widths, z-index and breakpoints — flattened into semantic CSS variables that swap in one atomic update.

1Define every group in one theme

All token groups live under the same tokens map and resolve together.
ts
1import { defineTheme } from "@theme-kit/core";
2
3const brand = defineTheme({
4  name: "brand-light",
5  tokens: {
6    colors: {
7      primary: "#6d28d9",
8      secondary: "#ede9fe",
9      mutedForeground: "#6b7280",
10    },
11    typography: {
12      fontFamilies: { sans: "Inter, system-ui, sans-serif" },
13      fontSizes: { base: "1rem", "4xl": "2.25rem" },
14      lineHeights: { normal: "1.5" },
15    },
16    spacing: { "1": "4px", "4": "16px", "8": "32px" },
17    radius: { md: "8px", xl: "16px", full: "9999px" },
18    shadows: { md: "0 4px 6px rgba(0,0,0,0.07)" },
19    borderWidths: { "1": "1px", "2": "2px" },
20    zIndex: { dropdown: "1000", modal: "1100" },
21    breakpoints: { md: "768px" },
22  },
23});
24
25// themeToCSSVariables(brand) emits --theme-color-primary,
26// --theme-typography-font-size-4xl, --theme-spacing-4,
27// --theme-radius-full, --theme-border-width-2 and more.

Adapters and build-time integrations consume the same resolved tokens — @theme-kit/tailwind maps them to --color-*, --radius-*, --spacing-*, --font-* and --shadow-* utilities.

Every theme validates against the full semantic color set — the base surfaces ( background, foreground, card, popover), interaction colors ( primary, secondary, accent, muted), and the status colors ( destructive, success) — each with its own *Foreground counterpart, plus border, input and ring. Missing any of them fails validateTheme.

2Token references & derived values

Tokens support references, expressions, and derived colors — all resolved at runtime.
ts
1import { defineTheme, resolveTokens } from "@theme-kit/core";
2
3const brand = defineTheme({
4  name: "brand",
5  tokens: {
6    colors: {
7      primary: "#6d28d9",
8      // Reference using $ prefix
9      primaryHover: "$colors.primary",
10      // Or using { } braces
11      ring: "{colors.primary}",
12      // Nested references work too
13      surface: {
14        primary: "$colors.primary",
15        hover: "{colors.primaryHover}",
16      },
17    },
18    spacing: {
19      "4": "16px",
20      // Expressions with calc()
21      "8": "calc($spacing.4 * 2)",
22    },
23  },
24});
25
26// Resolve all references to concrete values
27const resolved = resolveTokens(brand.tokens);
28// resolved.colors.primaryHover === "#6d28d9"
29// resolved.spacing["8"] === "32px"
ts
1import { defineTheme, resolveTokens } from "@theme-kit/core";
2
3const brand = defineTheme({
4  name: "brand",
5  tokens: {
6    colors: {
7      primary: "#6d28d9",
8      // Returns black or white based on WCAG luminance
9      primaryForeground: "contrast(#6d28d9)",
10      // Auto-derives readable foreground from base token
11      secondary: "#ede9fe",
12      secondaryForeground: "auto()",
13      // Works with references too
14      accent: "$colors.primary",
15      accentForeground: "auto($colors.primary)",
16    },
17  },
18});
19
20const resolved = resolveTokens(brand.tokens);
21// resolved.colors.primaryForeground === "#ffffff" (white on purple)
22// resolved.colors.secondaryForeground === "#1e1b4b" (dark on light purple)
ts
1import {
2  defineTheme,
3  extendTheme,
4  composeTheme,
5  mergeTokens,
6} from "@theme-kit/core";
7
8// Base theme with common tokens
9const base = defineTheme({
10  name: "base",
11  tokens: {
12    colors: {
13      background: "#ffffff",
14      foreground: "#0f172a",
15      primary: "#6366f1",
16    },
17    radius: { md: "8px", lg: "12px" },
18    spacing: { "4": "16px", "8": "32px" },
19  },
20});
21
22// Extend: create a variant with overrides
23const brandLight = extendTheme("brand-light", base, {
24  meta: { family: "brand", mode: "light" },
25  tokens: {
26    colors: {
27      primary: "#6d28d9",
28      accent: "#f5f3ff",
29    },
30    radius: { lg: "16px" },
31  },
32});
33
34// Compose: merge multiple themes into one
35const combined = composeTheme("combined", base, brandLight, {
36  tokens: { shadows: { md: "0 4px 6px rgba(0,0,0,0.1)" } },
37});
38
39// Low-level: merge token maps directly
40const customTokens = mergeTokens(brandLight.tokens, {
41  colors: { destructive: "#ef4444", success: "#16a34a" },
42  code: { background: "#f8f8f8" },
43});

3Token helpers — complete examples

The token API in @theme-kit/core — complete examples with output.
ts
1import { flattenTokens } from "@theme-kit/core";
2
3const tokens = {
4  colors: { primary: "#6366f1", surface: { hover: "#ede9fe" } },
5  spacing: { "4": "16px" },
6};
7
8const flat = flattenTokens(tokens);
9// {
10//   "colors.primary": "#6366f1",
11//   "colors.surface.hover": "#ede9fe",
12//   "spacing.4": "16px",
13// }
ts
1import { resolveTokens } from "@theme-kit/core";
2
3const tokens = {
4  colors: {
5    primary: "#6366f1",
6    ring: "$colors.primary",
7    surface: { primary: "{colors.primary}" },
8  },
9};
10
11const resolved = resolveTokens(tokens);
12// {
13//   colors: {
14//     primary: "#6366f1",
15//     ring: "#6366f1",
16//     surface: { primary: "#6366f1" },
17//   },
18// }
ts
1import { themeToCSSVariables } from "@theme-kit/core";
2
3const vars = themeToCSSVariables(brand);
4// {
5//   "--theme-color-primary": "#6d28d9",
6//   "--theme-color-secondary": "#ede9fe",
7//   "--theme-typography-font-family-sans": "Inter, system-ui, sans-serif",
8//   "--theme-spacing-4": "16px",
9//   "--theme-radius-lg": "12px",
10//   "--theme-code-background": "#161b22",
11//   "--theme-code-keyword": "#ff7b72",
12//   ...
13// }
14
15// Use with groups option for subset
16const colorVars = themeToCSSVariables(brand, { groups: ["colors"] });
17const codeVars = themeToCSSVariables(brand, { groups: ["code"] });
ts
1import { validateTheme, getBuiltInThemes } from "@theme-kit/core";
2
3const customTheme = defineTheme({
4  name: "custom",
5  tokens: { colors: { primary: "#6366f1" } }, // Missing required colors
6});
7
8const result = validateTheme(customTheme, { themes: getBuiltInThemes() });
9// {
10//   valid: false,
11//   issues: [
12//     { type: "missing", path: "colors.background", message: "Required color token missing" },
13//     { type: "missing", path: "colors.foreground", message: "Required color token missing" },
14//     ...
15//   ]
16// }
ts
1import { generateTheme } from "@theme-kit/core";
2
3// Generate complete light/dark pair from one seed color
4const { light, dark } = generateTheme({
5  seed: "#6366f1",           // Base brand color
6  family: "indigo",          // Family name
7  // Auto-generates: primary, secondary, muted, accent, border, ring
8  // Plus full typography, spacing, radius, shadows scales
9  // And harmonized code tokens for syntax highlighting
10});
11
12console.log(light.name);  // "indigo-light"
13console.log(dark.name);   // "indigo-dark"
14console.log(light.tokens.code); // Full code token set
Full signatures and parameter tables for every token function live in the @theme-kit/core API reference.

4Code Tokens

Dedicated tokens for syntax highlighting — background, keywords, strings, functions, types, and more.

Theme Kit includes a dedicated code token group with 22 semantic tokens for syntax highlighting. Every token maps to a --theme-code-* CSS variable that any highlighter (Shiki, Prism, etc.) can consume — so code blocks re-theme automatically when users switch themes, families, or modes.

Code Tokens Reference & Guide
Complete token reference, wiring guide, and best practices.

5Go deeper

Tokens are the input — here's what consumes them.
Semantic Tokens & Typography — Theme Kit