主题
使用 CSS 变量和全局样式自定义 HeroUI 的设计系统
HeroUI 使用 CSS 变量和 BEM 类来实现主题化。你可以使用标准 CSS 自定义从颜色到组件样式的所有内容。
想要创建你自己的主题? 试试 主题构建器,以可视化方式自定义颜色、圆角、字体等,然后导出 CSS 用于你的项目。
工作原理
HeroUI 的主题系统构建于 Tailwind CSS v4 的主题之上。当你导入 @heroui/styles 时,它会使用 Tailwind 的内置调色板,将其映射到语义化变量,自动在浅色和深色主题之间切换,并使用 CSS 层和 @theme 指令进行组织。
命名规则:
- 不带后缀的颜色用作背景(例如
--accent) - 带
-foreground后缀的颜色用于该背景上的文本(例如--accent-foreground)
快速开始
应用主题: 将主题类添加到 HTML 并将颜色应用到 body 上:
<html class="light" data-theme="light">
<body class="bg-background text-foreground">
<!-- Your app -->
</body>
</html>切换主题:
<!-- Light theme -->
<html class="light" data-theme="light">
<!-- Dark theme -->
<html class="dark" data-theme="dark">使用 next-themes 以编程方式切换主题(适用于 Next.js):
首先,用 ThemeProvider 包装你的应用:
// app/providers.tsx
"use client";
import { ThemeProvider } from "next-themes";
export function Providers({ children }: { children: React.ReactNode }) {
return (
<ThemeProvider attribute="class" defaultTheme="light">
{children}
</ThemeProvider>
);
}// app/layout.tsx
import { Providers } from "./providers";
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en" suppressHydrationWarning>
<body className="bg-background text-foreground">
<Providers>{children}</Providers>
</body>
</html>
);
}然后使用 useTheme 在主题之间切换:
"use client";
import { useTheme } from "next-themes";
export function ThemeSwitch() {
const { theme, setTheme } = useTheme();
return (
<button onClick={() => setTheme(theme === "dark" ? "light" : "dark")}>
Toggle {theme === "dark" ? "Light" : "Dark"} Mode
</button>
);
}覆盖颜色:
/* app/globals.css */
@import "tailwindcss";
@import "@heroui/styles";
:root {
/* Override any color variable */
--accent: oklch(0.7 0.25 260);
--success: oklch(0.65 0.15 155);
}注意:完整的调色板和视觉参考请参见 颜色。
深色模式:如需基于
next-themes与 HeroUIuseTheme钩子的完整配置指南,请参见 深色模式。
创建你自己的主题:
/* src/themes/ocean.css */
@layer base {
/* Ocean Light */
[data-theme="ocean"] {
color-scheme: light;使用你的主题:
/* app/globals.css */
@layer theme, base, components, utilities;
@import "tailwindcss";
@import "@heroui/styles";
@import "./src/themes/ocean.css" layer(theme); 应用你的主题:
<!-- index.html -->
<!-- Light ocean -->
<html data-theme="ocean">
<!-- Dark ocean -->
<html data-theme="ocean-dark">自定义组件
全局组件样式: 使用 BEM 类覆盖任何组件:
@layer components {
/* Customize buttons */
.button {
@apply font-semibold tracking-wide;
}
.button--primary {
@apply bg-blue-600 hover:bg-blue-700;
}
/* Customize accordions */
.accordion__trigger {
@apply text-lg font-bold;
}
}注意:完整的样式参考请参见 样式。
查找组件类名: 每个组件文档页面都会列出所有可用的类名(基类、修饰符、元素、状态)。示例:Button 类名
导入策略
完整导入(推荐): 两行代码即可获得全部内容:
@import "tailwindcss";
@import "@heroui/styles";按需导入: 只导入你需要的内容:
/* Define layers */
@layer theme, base, components, utilities;
/* Base requirements */
@import "tailwindcss";
@import "@heroui/styles/base" layer(base);
/* OR specific base file */
@import "@heroui/styles/base/base.css" layer(base);
/* Theme variables */
@import "@heroui/styles/themes/shared/theme.css" layer(theme);
@import "@heroui/styles/themes/default" layer(theme);
/* OR specific theme files */
@import "@heroui/styles/themes/default/index.css" layer(theme);
@import "@heroui/styles/themes/default/variables.css" layer(theme);
/* Components (all components) */
@import "@heroui/styles/components" layer(components);
/* OR specific component files */
@import "@heroui/styles/components/index.css" layer(components);
@import "@heroui/styles/components/button.css" layer(components);
@import "@heroui/styles/components/accordion.css" layer(components);
/* Utilities (optional) */
@import "@heroui/styles/utilities" layer(utilities);
/* Variants (optional) */
@import "@heroui/styles/variants" layer(utilities);注意:目录导入(例如
@heroui/styles/components)会自动解析为其对应的index.css文件。使用显式文件路径(例如@heroui/styles/components/button.css)来导入单个组件的样式。
Headless 模式: 从头开始构建你自己的样式:
@import "tailwindcss";
@import "@heroui/styles/base/base.css";
/* Your custom styles */
.button {
/* Your button styles */
}添加自定义颜色
将你自己的语义化颜色添加到主题中:
/* Define in both light and dark themes */
:root,
[data-theme="light"] {
--info: oklch(0.6 0.15 210);
--info-foreground: oklch(0.98 0 0);
}
.dark,
[data-theme="dark"] {
--info: oklch(0.7 0.12 210);
--info-foreground: oklch(0.15 0 0);
}
/* Make the color available to Tailwind */
@theme inline {
--color-info: var(--info);
--color-info-foreground: var(--info-foreground);
}现在你可以在组件中使用它:
<div className="bg-info text-info-foreground">Info message</div>变量参考
HeroUI 在 variables.css 中定义了三种类型的变量:
- 基础变量(Base Variables) — 不会变化的值,例如
--white、--black、间距以及排版 - 主题变量(Theme Variables) — 在浅色 / 深色主题之间切换的颜色,以及滚动条令牌(
--scrollbar-thumb、--scrollbar-width等) - 计算变量(Calculated Variables) — 悬停状态、柔和(soft)变体以及边框 / 分隔线层级(每个浅色 / 深色主题中的 Calculated Colors 区块,使用
color-mix()计算)
Tailwind 主题桥接(@theme inline):
themes/shared/theme.css 将语义化变量映射为 Tailwind 令牌(--color-*、--radius-*、--ease-*)。计算颜色引用的是 variables.css 中的底层变量(例如 --surface-hover、--accent-soft)—— 它们并不会在该文件中通过 color-mix() 内联展开:
@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
--color-surface: var(--surface);表单控件依赖 --field-* 主题变量。悬停、聚焦及边框变体定义于 variables.css 的 Calculated Colors 区块中,并在 theme.css 中映射到 Tailwind 令牌(例如 --color-field-hover: var(--field-hover))。在你的主题中覆盖 --field-background、--field-hover 及相关令牌,即可重新设计输入框、复选框、单选框和 OTP 输入槽的样式,而不会影响按钮或卡片等表面(surface)。
滚动条
HeroUI 为组件中的滚动区域(表格、弹出框、抽屉等)应用统一的滚动条样式。滚动条使用标准 CSS 属性(scrollbar-width、scrollbar-color、scrollbar-gutter),不再依赖 ::-webkit-scrollbar 覆盖。
模式 — 在 <html>、组件根元素或滚动插槽上设置 data-scrollbar:
| 模式 | data-scrollbar | 行为 |
|---|---|---|
| HeroUI 纤细 | (未设置) 或 thin | 使用主题令牌呈现的纤细滑块 |
| 操作系统 / 浏览器 | default | 原生滚动条(auto) |
| 隐藏 | none | 不显示滚动条(scrollbar-width: none) |
<!-- 全局使用原生滚动条 -->
<html data-scrollbar="default">
<!-- 在某个子树中恢复 HeroUI 滚动条 -->
<main data-scrollbar="thin">
...
</main>
<!-- 在某个子树中隐藏滚动条(例如弹出框) -->
<div data-scrollbar="none">
...
</div>主题变量 — 在 variables.css 的浅色与深色主题区块中定义:
| 变量 | 描述 |
|---|---|
--scrollbar-thumb | 滑块颜色(默认通过 color-mix 混入 15% 的 --foreground) |
--scrollbar-track | 轨道颜色(默认 transparent) |
--scrollbar-gutter | 滚动条间隙(默认 auto) |
--scrollbar-width | scrollbar-width 属性(默认 thin) |
--scrollbar-color | scrollbar-color 属性(默认为滑块颜色 + 轨道颜色) |
--scrollbar | --scrollbar-thumb 的旧版别名 |
全局自定义:
/* app/globals.css */
:root {
--scrollbar-thumb: color-mix(in oklch, var(--accent) 30%, transparent);
--scrollbar-gutter: auto;
}按滚动插槽 — 在组件上传入 data-scrollbar,或在外层包裹元素上覆盖相关令牌:
<Table data-scrollbar="default">
...
</Table>
<Drawer.Content data-scrollbar="thin" />
<Calendar.YearPickerGrid data-scrollbar="none" />自定义溢出区域 — 在自己的元素上使用 @heroui/styles 提供的 scrollbar、scrollbar-thin、scrollbar-default 或 scrollbar-none 工具类。基于类的覆盖方式详见 样式。
注意:部分组件默认隐藏滚动条(日期选择器弹出框、颜色选择器、次级标签页)。嵌套的滚动插槽(例如日期选择器内部的日历年份选择器)会保留 HeroUI 滚动条,因为
scrollbar-none只作用于其所在的元素本身,不会影响使用@apply scrollbar的后代元素。