始终使用语义化令牌,而不是原生的 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 变体用于内容后面的背景填充(例如 Badge 或 Banner)。
令牌 用途 bg-kumo-info信息指示器 bg-kumo-success成功指示器 bg-kumo-warning警告指示器 bg-kumo-danger错误/破坏性操作指示器
状态点使用实色令牌 bg-kumo-*,图标使用 fill-kumo-*,边框和描边使用 border-kumo-*、ring-kumo-*。Banner 和徽章使用具有不同不透明度的 -tint 变体。
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
Light var(--color-neutral-900, oklch(21% 0.006 285.885))
Dark var(--color-neutral-100, oklch(97% 0 0))
--text-color-kumo-inverse
Light var(--color-neutral-100, oklch(97% 0 0))
Dark var(--color-neutral-900, oklch(20.5% 0 0))
--text-color-kumo-strong
Light var(--color-neutral-950, oklch(14.5% 0 0))
Dark var(--color-neutral-50, oklch(98.5% 0 0))
--text-color-kumo-subtle
Light var(--color-neutral-500, oklch(55.6% 0 0))
Dark var(--color-neutral-400, oklch(70.8% 0 0))
--text-color-kumo-inactive
Light var(--color-neutral-300, oklch(87% 0 0))
Dark var(--color-neutral-600, oklch(43.9% 0 0))
--text-color-kumo-placeholder
Light var(--color-neutral-400, oklch(70.8% 0 0))
Dark var(--color-neutral-500, oklch(55.6% 0 0))
--text-color-kumo-link
Light var(--color-blue-800, oklch(42.4% 0.199 265.638))
Dark var(--color-blue-400, oklch(70.7% 0.165 254.624))
--text-color-kumo-info
Light var(--color-blue-800, oklch(42.4% 0.199 265.638))
Dark var(--color-blue-400, oklch(70.7% 0.165 254.624))
--text-color-kumo-success
Light var(--color-emerald-800, oklch(43.2% 0.095 166.913))
Dark var(--color-emerald-200, oklch(90.5% 0.093 164.15))
--text-color-kumo-danger
Light var(--color-red-700, oklch(50.5% 0.213 27.518))
Dark var(--color-red-400, oklch(70.4% 0.191 22.216))
--text-color-kumo-warning
Light oklch(59.7% 0.144 57.5)
Dark var(--color-orange-400, oklch(75% 0.183 55.934))
Surface, State & Theme Colors (28) --color-kumo-canvas
Light var(--color-kumo-neutral-25, oklch(98.75% 0 0))
Dark var(--color-kumo-neutral-1000, oklch(10% 0 0))
--color-kumo-elevated
Light var(--color-kumo-neutral-75, oklch(98% 0 0))
Dark var(--color-kumo-neutral-975, oklch(12% 0 0))
--color-kumo-recessed
Light var(--color-kumo-neutral-125, oklch(96% 0 0))
Dark var(--color-kumo-neutral-950, oklch(15% 0 0))
--color-kumo-base
Light var(--color-white, #fff)
Dark var(--color-kumo-neutral-925, oklch(17% 0 0))
--color-kumo-tint
Light var(--color-neutral-100, oklch(97% 0 0))
Dark var(--color-kumo-neutral-800, oklch(26.9% 0 0))
--color-kumo-contrast
Light var(--color-kumo-neutral-975, oklch(8.5% 0 0))
Dark var(--color-kumo-neutral-25, oklch(98.5% 0 0))
--color-kumo-overlay
Light var(--color-kumo-neutral-50, oklch(97.5% 0 0))
Dark var(--color-neutral-800, oklch(26.9% 0 0))
--color-kumo-control
Light var(--color-white, #fff)
Dark var(--color-neutral-900, oklch(21% 0.006 285.885))
--color-kumo-interact
Light var(--color-neutral-300, oklch(87% 0 0))
Dark var(--color-neutral-700, oklch(37.1% 0 0))
--color-kumo-fill
Light var(--color-neutral-200, oklch(92.2% 0 0))
Dark var(--color-neutral-800, oklch(26.9% 0 0))
--color-kumo-fill-hover
Light var(--color-kumo-neutral-125, oklch(96.5% 0 0))
Dark var(--color-neutral-800, oklch(37.1% 0 0))
--color-kumo-brand
Light oklch(0.5772 0.2324 260)
Dark color-mix(in oklch, oklch(0.5772 0.2324 260), black 10%)
--color-kumo-brand-hover
Light var(--color-blue-700, oklch(48.8% 0.243 264.376))
Dark var(--color-blue-700, oklch(48.8% 0.243 264.376))
--color-kumo-line
Light oklch(14.5% 0 0 / 0.1)
Dark var(--color-kumo-neutral-750, oklch(32% 0 0))
--color-kumo-hairline
Light var(--color-kumo-neutral-150, oklch(93.5% 0 0))
Dark var(--color-neutral-800, oklch(26.9% 0 0))
--color-kumo-focus
Light var(--color-kumo-neutral-950, oklch(15% 0 0))
Dark var(--color-kumo-neutral-150, oklch(93.5% 0 0))
--color-kumo-shadow-edge
Light oklch(0% 0 0 / 0.12)
Dark oklch(100% 0 0 / 0.1)
--color-kumo-shadow-drop
Light oklch(0% 0 0 / 0.08)
--color-kumo-arrow-edge
Light oklch(14.5% 0 0 / 0.1)
--color-kumo-arrow-stroke
Dark var(--color-kumo-neutral-750, oklch(32% 0 0))
--color-kumo-info-tint
Light oklch(93.2% 0.032 255.6 / 0.45)
Dark oklch(38.0% 0.145 265.5 / 0.22)
--color-kumo-info
Light var(--color-blue-500, oklch(68.5% 0.169 237.323))
Dark var(--color-blue-500, oklch(68.5% 0.169 237.323))
--color-kumo-warning-tint
Light oklch(93.1% 0.107 94.6 / 0.20)
Dark oklch(35.3% 0.079 65.0 / 0.37)
--color-kumo-warning
Light oklch(73.9% 0.177 58.2)
Dark oklch(64.5% 0.168 50.0)
--color-kumo-danger-tint
Light oklch(93.6% 0.032 17.7 / 0.42)
Dark oklch(42.9% 0.176 28.7 / 0.17)
--color-kumo-danger
Light var(--color-red-500, oklch(63.7% 0.237 25.331))
Dark var(--color-red-600, oklch(57.7% 0.245 27.325))
--color-kumo-success-tint
Light oklch(96.2% 0.043 156.7 / 0.57)
Dark oklch(39.3% 0.096 152.3 / 0.20)
--color-kumo-success
Light var(--color-emerald-600, oklch(59.6% 0.145 163.225))
Dark var(--color-emerald-400, oklch(76.5% 0.177 163.223))
Component Colors (14) Badge (12) --text-color-kumo-badge-orange-subtle
Light var(--color-orange-800, oklch(47% 0.157 37.304))
Dark var(--color-orange-200, oklch(90.1% 0.076 70.697))
--text-color-kumo-badge-teal-subtle
Light var(--color-teal-800, oklch(43.7% 0.078 188.216))
Dark var(--color-teal-200, oklch(91% 0.096 180.426))
--text-color-kumo-badge-neutral-subtle
Light var(--color-neutral-800, oklch(26.9% 0 0))
Dark var(--color-neutral-200, oklch(92.2% 0 0))
--text-color-kumo-badge-inverted
Light var(--color-white, #fff)
Dark var(--color-black, #000)
--color-kumo-badge-red
Light var(--color-red-600, oklch(57.7% 0.245 27.325))
Dark var(--color-red-700, oklch(50.5% 0.213 27.518))
--color-kumo-badge-green
Light var(--color-emerald-600, oklch(59.6% 0.145 163.225))
Dark var(--color-emerald-700, oklch(50.8% 0.118 165.612))
--color-kumo-badge-orange
Light var(--color-orange-650, oklch(81.5% 0.197 76))
Dark var(--color-orange-650, oklch(81.5% 0.197 76))
--color-kumo-badge-purple
Light var(--color-purple-600, oklch(55.8% 0.288 302.321))
Dark var(--color-purple-700, oklch(49.6% 0.265 301.924))
--color-kumo-badge-teal
Light var(--color-teal-650, oklch(54.9% 0.096 184.565))
Dark var(--color-teal-700, oklch(51.1% 0.096 186.391))
--color-kumo-badge-blue
Light var(--color-blue-600, oklch(54.6% 0.245 262.881))
Dark var(--color-blue-700, oklch(48.8% 0.243 264.376))
--color-kumo-badge-neutral
Light var(--color-neutral-500, oklch(55.6% 0 0))
Dark var(--color-neutral-600, oklch(43.9% 0 0))
--color-kumo-badge-inverted
Light var(--color-neutral-950, oklch(14.5% 0 0))
Dark var(--color-white, #fff)
Banner (2) --color-kumo-banner-info
Light oklch(93.2% 0.032 255.585 / 0.7)
Dark oklch(37.9% 0.146 265.522 / 0.5)
--color-kumo-banner-warning
Light var(--color-yellow-100, oklch(97.3% 0.071 103.193))
Dark oklch(55.4% 0.135 66.442 / 0.5)