Usage

Always use semantic tokens instead of raw Tailwind colors. This ensures your UI automatically adapts to light and dark mode.

Correct

<div className="bg-kumo-base text-kumo-default border-kumo-line">
  <button className="bg-kumo-brand text-white">Primary</button>
  <button className="bg-kumo-control text-kumo-default">Secondary</button>
</div>

Incorrect

<!-- Never use raw Tailwind colors -->
<div className="bg-white dark:bg-gray-900 text-black dark:text-white">
  <button className="bg-blue-500">Primary</button>
</div>
Lint rules enforce this: The no-primitive-colors rule will flag any raw Tailwind colors like bg-blue-500.

Mode

Set data-mode on a parent element to force light or dark. If you omit it in your app, Kumo's shipped CSS follows the current browser/system preference by default.

data-mode="light"

data-mode="dark"

data-mode omitted

follows browser / OS preference

// Default: follow browser / system preference
<html data-theme="kumo">

// Optional overrides
<html data-theme="kumo" data-mode="light">
<html data-theme="kumo" data-mode="dark">

// Components automatically adapt - no dark: variants needed
<div className="bg-kumo-base text-kumo-default" />

Themes

Themes override semantic token values while preserving the same token names. Set data-theme on a parent element to apply a theme.

data-theme="kumo"

data-theme="fedramp"

// Apply a theme to a section or the whole app
<div data-theme="fedramp">
  {/* All Kumo components inside use fedramp token overrides */}
  <Button>fedramp Styled</Button>
</div>

// Themes work with both light and dark mode
<html data-mode="dark" data-theme="fedramp">

Theme Generator

Themes are defined in a centralized config and generated as CSS files plus machine-readable metadata. The generator keeps package exports and docs in sync.

# List all tokens and their theme overrides
pnpm --filter @cloudflare/kumo codegen:themes --list

# Generate theme CSS files
pnpm --filter @cloudflare/kumo codegen:themes

# Inspect generated theme metadata
cat packages/kumo/ai/theme-metadata.json

# Preview changes without writing files
pnpm --filter @cloudflare/kumo codegen:themes --dry-run

Theme config: packages/kumo/scripts/theme-generator/config.ts

Creating a New Theme

Add theme overrides in the config file. Only override tokens that need to change—all other tokens inherit from the base kumo theme.

// In scripts/theme-generator/config.ts
export const THEME_CONFIG: ThemeConfig = {
  color: {
    "kumo-base": {
      newName: "",
      theme: {
        kumo: {
          light: "var(--color-white, #fff)",
          dark: "var(--color-black, #000)",
        },
        // Add your theme override
        myTheme: {
          light: "#f0f4f8",
          dark: "#1a1f2e",
        },
      },
    },
    // ... other tokens
  },
};

// Add to available themes
export const AVAILABLE_THEMES = ["kumo", "fedramp", "myTheme"] as const;

Then run pnpm codegen:themes to generate the CSS and metadata. Make sure the generated theme stylesheet is imported before using the new data-theme value.

Adding Tokens

If no existing semantic token fits, add a new token in the theme config instead of hardcoding a hex value in a component.

// 1. Add the token in packages/kumo/scripts/theme-generator/config.ts
"kumo-card": {
  newName: "",
  theme: {
    kumo: {
      light: "var(--color-kumo-neutral-25, oklch(98.5% 0 0))",
      dark: "var(--color-kumo-neutral-900, oklch(20% 0 0))",
    },
  },
}

// 2. Regenerate theme outputs
pnpm --filter @cloudflare/kumo codegen:themes

// 3. Use the semantic class in components
<div className="bg-kumo-base border-kumo-line text-kumo-default" />
  • Source of truth: config.ts
  • Generated outputs: src/styles/theme-*.css and ai/theme-metadata.json
  • Available classnames follow the token name: bg-kumo-base, text-kumo-default, border-kumo-line, ring-kumo-ring

Token Reference

Use the mode toggle in the header to inspect light and dark values. The token values shown below are generated from Kumo theme metadata.

Colors

Displaying 36 semantic tokens

Text Colors (11)

kumo-default
Lightvar(--color-neutral-900, oklch(21% 0.006 285.885))
Darkvar(--color-neutral-100, oklch(97% 0 0))
kumo-inverse
Lightvar(--color-neutral-100, oklch(97% 0 0))
Darkvar(--color-neutral-900, oklch(20.5% 0 0))
kumo-strong
Lightvar(--color-neutral-600, oklch(43.9% 0 0))
Darkvar(--color-neutral-400, oklch(70.8% 0 0))
kumo-subtle
Lightvar(--color-neutral-500, oklch(55.6% 0 0))
Darkvar(--color-kumo-neutral-50, oklch(97.5% 0 0))
kumo-inactive
Lightvar(--color-neutral-400, oklch(70.8% 0 0))
Darkvar(--color-neutral-600, oklch(70.8% 0 0))
kumo-placeholder
Lightvar(--color-neutral-400, oklch(70.8% 0 0))
Darkvar(--color-neutral-500, oklch(55.6% 0 0))
kumo-brand
Light#f6821f
Dark#f6821f
kumo-link
Lightvar(--color-blue-800, oklch(42.4% 0.199 265.638))
Darkvar(--color-blue-400, oklch(70.7% 0.165 254.624))
kumo-success
Lightvar(--color-green-500, oklch(72.3% 0.219 149.579))
Darkvar(--color-green-400, oklch(79.2% 0.209 151.711))
kumo-danger
Lightvar(--color-red-500, oklch(63.7% 0.237 25.331))
Darkvar(--color-red-400, oklch(70.4% 0.191 22.216))
kumo-warning
Lightvar(--color-yellow-800, oklch(47.6% 0.114 61.907))
Darkvar(--color-yellow-400, oklch(85.2% 0.199 91.936))

Surface, State & Theme Colors (25)

kumo-surface
Lightvar(--color-kumo-neutral-25, oklch(99% 0 0))
Darkvar(--color-kumo-neutral-975, oklch(8.5% 0 0))
kumo-recessed
Lightvar(--color-kumo-neutral-50, oklch(97.5% 0 0))
Darkvar(--color-kumo-neutral-925, oklch(18% 0 0))
kumo-base
Lightvar(--color-white, #fff)
Darkvar(--color-kumo-neutral-850, oklch(22.4% 0 0))
kumo-tint
Lightvar(--color-kumo-neutral-75, oklch(96.7% 0 0))
Darkvar(--color-kumo-neutral-800, oklch(26.9% 0 0))
kumo-contrast
Lightvar(--color-kumo-neutral-975, oklch(8.5% 0 0))
Darkvar(--color-kumo-neutral-25, oklch(99% 0 0))
kumo-elevated
Lightvar(--color-kumo-neutral-25, oklch(98.5% 0 0))
Darkvar(--color-neutral-950, oklch(14.5% 0 0))
kumo-overlay
Lightvar(--color-kumo-neutral-50, oklch(97.5% 0 0))
Darkvar(--color-neutral-800, oklch(26.9% 0 0))
kumo-control
Lightvar(--color-white, #fff)
Darkvar(--color-neutral-900, oklch(21% 0.006 285.885))
kumo-interact
Lightvar(--color-neutral-300, oklch(87% 0 0))
Darkvar(--color-neutral-700, oklch(37.1% 0 0))
kumo-fill
Lightvar(--color-neutral-200, oklch(92.2% 0 0))
Darkvar(--color-neutral-800, oklch(26.9% 0 0))
kumo-fill-hover
Lightvar(--color-neutral-200, oklch(92.2% 0 0))
Darkvar(--color-neutral-700, oklch(37.1% 0 0))
kumo-line
Lightoklch(14.5% 0 0 / 0.1)
Darkvar(--color-neutral-800, oklch(26.9% 0 0))
kumo-ring
Lightvar(--color-kumo-neutral-150, oklch(93.5% 0 0))
Darkvar(--color-neutral-700, oklch(37.1% 0 0))
kumo-tip-shadow
Lightvar(--color-gray-200, oklch(92.8% 0.006 264.531))
Darktransparent
kumo-tip-stroke
Lighttransparent
Darkvar(--color-neutral-800, oklch(26.9% 0 0))
kumo-brand
Lightoklch(0.5772 0.2324 260)
Darkoklch(0.5772 0.2324 260)
kumo-brand-hover
Lightvar(--color-blue-700, oklch(48.8% 0.243 264.376))
Darkvar(--color-blue-700, oklch(48.8% 0.243 264.376))
kumo-info
Lightvar(--color-blue-500, oklch(62.3% 0.214 259.815))
Darkvar(--color-blue-400, oklch(70.7% 0.165 254.624))
kumo-info-tint
Lightvar(--color-blue-300, oklch(80.9% 0.105 251.813))
Darkvar(--color-blue-900, oklch(37.9% 0.146 265.522))
kumo-warning
Lightvar(--color-yellow-500, oklch(79.5% 0.184 86.047))
Darkvar(--color-yellow-700, oklch(55.4% 0.135 66.442))
kumo-warning-tint
Lightvar(--color-yellow-300, oklch(90.5% 0.182 98.111))
Darkvar(--color-yellow-900, oklch(42.1% 0.095 57.708))
kumo-danger
Lightvar(--color-red-500, oklch(63.7% 0.237 25.331))
Darkvar(--color-red-700, oklch(50.5% 0.213 27.518))
kumo-danger-tint
Lightvar(--color-red-300, oklch(80.8% 0.114 19.571))
Darkvar(--color-red-900, oklch(39.6% 0.141 25.723))
kumo-success
Lightvar(--color-green-500, oklch(72.3% 0.219 149.579))
Darkvar(--color-green-700, oklch(52.7% 0.154 150.069))
kumo-success-tint
Lightvar(--color-green-300, oklch(87.1% 0.15 154.449))
Darkvar(--color-green-900, oklch(39.3% 0.095 152.535))