用法

始终使用语义化令牌,而不是原生的 Tailwind 颜色。这样可以确保你的 UI 自动适配浅色和深色模式,并保持组件在不同主题下的一致性。

正确

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

错误

{
  /* 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)规则会强制这一点:no-primitive-colors 规则会标记任何原生 Tailwind 颜色,如 bg-blue-500

模式

在父元素上设置 data-mode 来控制浅色/深色模式。切勿使用 Tailwind 的 dark: 变体 — 语义化令牌会通过 CSS light-dark() 自动处理深色模式。

// Set mode on html or body
<html data-mode="light">  // Light mode
<html data-mode="dark">   // Dark mode

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

主题

主题在保留相同令牌名的同时覆盖语义令牌值。在父元素上设置 data-theme 即可应用主题。

可用主题

  • kumo — 默认主题(无需设置属性)
  • 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">

主题生成器

主题在集中式配置中定义,并生成 CSS 文件。主题生成器可确保所有主题之间保持一致。


# List all tokens and their theme overrides

pnpm --filter @cloudflare/kumo codegen:themes --list

# Generate theme CSS files

pnpm --filter @cloudflare/kumo codegen:themes

# Preview changes without writing files

pnpm --filter @cloudflare/kumo codegen:themes --dry-run

主题配置:packages/kumo/scripts/theme-generator/config.ts

创建新主题

在配置文件中添加主题覆盖项。只需覆盖需要变更的令牌 — 其余令牌都会继承基础 kumo 主题。

// 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;

然后运行 pnpm codegen:themes 生成 CSS。

语义化令牌

我们使用语义化令牌按用途对颜色进行分组。请选择与元素角色匹配的令牌,而不是你想要的某个颜色。

语义化令牌按角色命名,而不是按色相。像 bg-kumo-danger 这样的令牌表达的是意图 — 它不意味着某种特定的红色,其具体值可以随主题或颜色模式变化,而无需改动你的组件代码。

表面层级

表面用于建立 UI 中的深度和分层。请按照从最外层背景向内的顺序使用它们。

令牌用途
bg-kumo-canvas最外层的页面背景 — 位于所有内容之后
bg-kumo-base组件默认背景
bg-kumo-elevated略微抬升的表面,例如 LayerCard.Secondary
bg-kumo-recessed带有更暗填充的内凹表面,例如分段式 Tabs 的背景
bg-kumo-tint用于表格或悬停状态的细微着色背景
bg-kumo-contrast高对比度的反相背景

品牌色

令牌用途
bg-kumo-brand主要品牌背景
bg-kumo-brand-hover品牌背景的悬停状态

语义化状态颜色

每种状态颜色都有两个变体:实色用于图标和指示器,-tint 变体用于内容后面的背景填充(例如 BadgeBanner)。

令牌用途
bg-kumo-info信息指示器
bg-kumo-success成功指示器
bg-kumo-warning警告指示器
bg-kumo-danger错误/破坏性操作指示器

状态点使用实色令牌 bg-kumo-*,图标使用 fill-kumo-*,边框和描边使用 border-kumo-*ring-kumo-*。Banner 和徽章使用具有不同不透明度的 -tint 变体。

Something went wrong.
import { WarningIcon } from "@phosphor-icons/react";

export function StatusBannerDemo() {
  return (
    <div className="flex items-center gap-2 rounded-lg bg-kumo-danger-tint/70 p-4">
      <WarningIcon weight="fill" className="fill-kumo-danger" />
      <span className="text-sm text-kumo-danger">Something went wrong.</span>
    </div>
  );
}

文本颜色

令牌用途
text-kumo-default正文主文本
text-kumo-strong比默认更强的文本对比,用于标题和重要标签
text-kumo-subtle用于描述、说明文字或次要标签的弱化文本
text-kumo-inactive已禁用或不活跃的文本
text-kumo-placeholder输入框中的占位提示文本
text-kumo-inverse用于高对比度或反相背景上的文本
text-kumo-link链接文本
text-kumo-info信息色文本
text-kumo-success成功色文本
text-kumo-warning警告色文本
text-kumo-danger错误/破坏性操作文本

语义文本颜色(例如 text-kumo-success)默认更深,以便在 tint-* 背景上提供更好的对比度和可读性。

边框与描边

令牌用途
kumo-hairline用于区分没有阴影的平面表面的边框/描边颜色(例如 LayerCard)。
kumo-line更粗的边框/描边颜色,与阴影一起勾勒出抬升表面的边缘。

令牌参考

切换页面顶部的主题开关,查看令牌如何适配。标记为 global 的令牌是显式启用的类,无论任何主题都可用。

Colors

Displaying 54 tokens

Text Colors (12)

--text-color-kumo-default
Lightvar(--color-neutral-900, oklch(21% 0.006 285.885))
Darkvar(--color-neutral-100, oklch(97% 0 0))
--text-color-kumo-inverse
Lightvar(--color-neutral-100, oklch(97% 0 0))
Darkvar(--color-neutral-900, oklch(20.5% 0 0))
--text-color-kumo-strong
Lightvar(--color-neutral-950, oklch(14.5% 0 0))
Darkvar(--color-neutral-50, oklch(98.5% 0 0))
--text-color-kumo-subtle
Lightvar(--color-neutral-500, oklch(55.6% 0 0))
Darkvar(--color-neutral-400, oklch(70.8% 0 0))
--text-color-kumo-inactive
Lightvar(--color-neutral-300, oklch(87% 0 0))
Darkvar(--color-neutral-600, oklch(43.9% 0 0))
--text-color-kumo-placeholder
Lightvar(--color-neutral-400, oklch(70.8% 0 0))
Darkvar(--color-neutral-500, oklch(55.6% 0 0))
--text-color-kumo-brand
Light#f6821f
Dark#f6821f
--text-color-kumo-link
Lightvar(--color-blue-800, oklch(42.4% 0.199 265.638))
Darkvar(--color-blue-400, oklch(70.7% 0.165 254.624))
--text-color-kumo-info
Lightvar(--color-blue-800, oklch(42.4% 0.199 265.638))
Darkvar(--color-blue-400, oklch(70.7% 0.165 254.624))
--text-color-kumo-success
Lightvar(--color-emerald-800, oklch(43.2% 0.095 166.913))
Darkvar(--color-emerald-200, oklch(90.5% 0.093 164.15))
--text-color-kumo-danger
Lightvar(--color-red-700, oklch(50.5% 0.213 27.518))
Darkvar(--color-red-400, oklch(70.4% 0.191 22.216))
--text-color-kumo-warning
Lightoklch(59.7% 0.144 57.5)
Darkvar(--color-orange-400, oklch(75% 0.183 55.934))

Surface, State & Theme Colors (28)

--color-kumo-canvas
Lightvar(--color-kumo-neutral-25, oklch(98.75% 0 0))
Darkvar(--color-kumo-neutral-1000, oklch(10% 0 0))
--color-kumo-elevated
Lightvar(--color-kumo-neutral-75, oklch(98% 0 0))
Darkvar(--color-kumo-neutral-975, oklch(12% 0 0))
--color-kumo-recessed
Lightvar(--color-kumo-neutral-125, oklch(96% 0 0))
Darkvar(--color-kumo-neutral-950, oklch(15% 0 0))
--color-kumo-base
Lightvar(--color-white, #fff)
Darkvar(--color-kumo-neutral-925, oklch(17% 0 0))
--color-kumo-tint
Lightvar(--color-neutral-100, oklch(97% 0 0))
Darkvar(--color-kumo-neutral-800, oklch(26.9% 0 0))
--color-kumo-contrast
Lightvar(--color-kumo-neutral-975, oklch(8.5% 0 0))
Darkvar(--color-kumo-neutral-25, oklch(98.5% 0 0))
--color-kumo-overlay
Lightvar(--color-kumo-neutral-50, oklch(97.5% 0 0))
Darkvar(--color-neutral-800, oklch(26.9% 0 0))
--color-kumo-control
Lightvar(--color-white, #fff)
Darkvar(--color-neutral-900, oklch(21% 0.006 285.885))
--color-kumo-interact
Lightvar(--color-neutral-300, oklch(87% 0 0))
Darkvar(--color-neutral-700, oklch(37.1% 0 0))
--color-kumo-fill
Lightvar(--color-neutral-200, oklch(92.2% 0 0))
Darkvar(--color-neutral-800, oklch(26.9% 0 0))
--color-kumo-fill-hover
Lightvar(--color-kumo-neutral-125, oklch(96.5% 0 0))
Darkvar(--color-neutral-800, oklch(37.1% 0 0))
--color-kumo-brand
Lightoklch(0.5772 0.2324 260)
Darkcolor-mix(in oklch, oklch(0.5772 0.2324 260), black 10%)
--color-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))
--color-kumo-line
Lightoklch(14.5% 0 0 / 0.1)
Darkvar(--color-kumo-neutral-750, oklch(32% 0 0))
--color-kumo-hairline
Lightvar(--color-kumo-neutral-150, oklch(93.5% 0 0))
Darkvar(--color-neutral-800, oklch(26.9% 0 0))
--color-kumo-focus
Lightvar(--color-kumo-neutral-950, oklch(15% 0 0))
Darkvar(--color-kumo-neutral-150, oklch(93.5% 0 0))
--color-kumo-shadow-edge
Lightoklch(0% 0 0 / 0.12)
Darkoklch(100% 0 0 / 0.1)
--color-kumo-shadow-drop
Lightoklch(0% 0 0 / 0.08)
Darkoklch(0% 0 0 / 0.3)
--color-kumo-arrow-edge
Lightoklch(14.5% 0 0 / 0.1)
Darktransparent
--color-kumo-arrow-stroke
Lighttransparent
Darkvar(--color-kumo-neutral-750, oklch(32% 0 0))
--color-kumo-info-tint
Lightoklch(93.2% 0.032 255.6 / 0.45)
Darkoklch(38.0% 0.145 265.5 / 0.22)
--color-kumo-info
Lightvar(--color-blue-500, oklch(68.5% 0.169 237.323))
Darkvar(--color-blue-500, oklch(68.5% 0.169 237.323))
--color-kumo-warning-tint
Lightoklch(93.1% 0.107 94.6 / 0.20)
Darkoklch(35.3% 0.079 65.0 / 0.37)
--color-kumo-warning
Lightoklch(73.9% 0.177 58.2)
Darkoklch(64.5% 0.168 50.0)
--color-kumo-danger-tint
Lightoklch(93.6% 0.032 17.7 / 0.42)
Darkoklch(42.9% 0.176 28.7 / 0.17)
--color-kumo-danger
Lightvar(--color-red-500, oklch(63.7% 0.237 25.331))
Darkvar(--color-red-600, oklch(57.7% 0.245 27.325))
--color-kumo-success-tint
Lightoklch(96.2% 0.043 156.7 / 0.57)
Darkoklch(39.3% 0.096 152.3 / 0.20)
--color-kumo-success
Lightvar(--color-emerald-600, oklch(59.6% 0.145 163.225))
Darkvar(--color-emerald-400, oklch(76.5% 0.177 163.223))

Component Colors (14)

Badge (12)

--text-color-kumo-badge-orange-subtle
Lightvar(--color-orange-800, oklch(47% 0.157 37.304))
Darkvar(--color-orange-200, oklch(90.1% 0.076 70.697))
--text-color-kumo-badge-teal-subtle
Lightvar(--color-teal-800, oklch(43.7% 0.078 188.216))
Darkvar(--color-teal-200, oklch(91% 0.096 180.426))
--text-color-kumo-badge-neutral-subtle
Lightvar(--color-neutral-800, oklch(26.9% 0 0))
Darkvar(--color-neutral-200, oklch(92.2% 0 0))
--text-color-kumo-badge-inverted
Lightvar(--color-white, #fff)
Darkvar(--color-black, #000)
--color-kumo-badge-red
Lightvar(--color-red-600, oklch(57.7% 0.245 27.325))
Darkvar(--color-red-700, oklch(50.5% 0.213 27.518))
--color-kumo-badge-green
Lightvar(--color-emerald-600, oklch(59.6% 0.145 163.225))
Darkvar(--color-emerald-700, oklch(50.8% 0.118 165.612))
--color-kumo-badge-orange
Lightvar(--color-orange-650, oklch(81.5% 0.197 76))
Darkvar(--color-orange-650, oklch(81.5% 0.197 76))
--color-kumo-badge-purple
Lightvar(--color-purple-600, oklch(55.8% 0.288 302.321))
Darkvar(--color-purple-700, oklch(49.6% 0.265 301.924))
--color-kumo-badge-teal
Lightvar(--color-teal-650, oklch(54.9% 0.096 184.565))
Darkvar(--color-teal-700, oklch(51.1% 0.096 186.391))
--color-kumo-badge-blue
Lightvar(--color-blue-600, oklch(54.6% 0.245 262.881))
Darkvar(--color-blue-700, oklch(48.8% 0.243 264.376))
--color-kumo-badge-neutral
Lightvar(--color-neutral-500, oklch(55.6% 0 0))
Darkvar(--color-neutral-600, oklch(43.9% 0 0))
--color-kumo-badge-inverted
Lightvar(--color-neutral-950, oklch(14.5% 0 0))
Darkvar(--color-white, #fff)

Banner (2)

--color-kumo-banner-info
Lightoklch(93.2% 0.032 255.585 / 0.7)
Darkoklch(37.9% 0.146 265.522 / 0.5)
--color-kumo-banner-warning
Lightvar(--color-yellow-100, oklch(97.3% 0.071 103.193))
Darkoklch(55.4% 0.135 66.442 / 0.5)