- 手风琴
- 提示
- 警告对话框
- 宽高比
- 头像
- 徽章
- 面包屑导航
- 按钮
- 按钮组
- 日历 Calendar
- 卡片
- Carousel
- 图表 Chart
- 复选框
- 折叠面板
- 组合框
- 命令
- 上下文菜单
- 数据表格 Data Table
- 日期选择器 Date Picker
- 对话框 Dialog
- 抽屉
- 下拉菜单
- Empty
- 字段
- 悬停卡片
- 输入
- 输入组
- 输入 OTP
- 项目
- Kbd
- 标签
- 菜单栏
- 原生选择框
- 导航菜单 Navigation Menu
- 分页
- 弹出框
- 进度 Progress
- 单选框组
- 可调整大小
- 滚动区域 Scroll Area
- 选择框
- 分隔符 Separator
- 侧边栏 Sheet
- 侧边栏 Sidebar
- 骨架屏
- 滑块
- Sonner
- 加载指示器 Spinner
- 开关
- 表格
- 标签页 Tabs
- 文本域
- 吐司
- 切换按钮 Toggle
- 切换组
- 提示 Tooltip
- 排版
2025年10月 - 新组件
旋转器(Spinner)、键盘按键(Kbd)、按钮组(Button Group)、输入组(Input Group)、表单字段(Field)、项(Item)和空状态组件(Empty)。
这轮新组件,我关注了我们每天都在做的事情,那些无趣而重复构建的基础内容,并做了真正可重用的抽象组件。
这些组件兼容所有组件库,Radix、Base UI、React Aria,随你喜欢。复制粘贴直接用到你的项目里。
- 旋转器(Spinner):显示加载状态的指示器。
- 键盘按键(Kbd):显示单个按键或一组合按键。
- 按钮组(Button Group):将相关按钮分组,用于操作组和拆分按钮。
- 输入组(Input Group):带图标、按钮、标签等的输入框组合。
- 表单字段(Field):一个组件搞定所有表单。
- 项(Item):用于显示列表项、卡片等。
- 空状态(Empty):用于展示空状态的组件。
Spinner
先从最简单的开始:Spinner 和 Kbd。非常基础,我们都知道它们是干什么的。
下面是如何渲染一个旋转器:
import { Spinner } from "@/components/ui/spinner"<Spinner />效果如下:
import { Spinner } from "@/components/ui/spinner"
export function SpinnerBasic() {放到按钮里是什么样子:
import { Button } from "@/components/ui/button"
import { Spinner } from "@/components/ui/spinner"
你可以编辑代码替换成你自己的旋转器。
import { LoaderIcon } from "lucide-react"
import { cn } from "@/lib/utils"Kbd
Kbd 是一个渲染键盘按键的组件。
import { Kbd, KbdGroup } from "@/components/ui/kbd"<Kbd>Ctrl</Kbd>使用 KbdGroup 可以将多个按键组合在一起。
<KbdGroup>
<Kbd>Ctrl</Kbd>
<Kbd>B</Kbd>
</KbdGroup>import { Kbd, KbdGroup } from "@/components/ui/kbd"
export function KbdDemo() {你可以将它添加到按钮、提示气泡、输入组等。
Button Group
收到了很多关于这个的请求:按钮组(Button Group)。它是一个容器,将相关按钮以统一样式分组。非常适合操作组、拆分按钮等场景。
"use client"
import * as React from "react"代码如下:
import { ButtonGroup } from "@/components/ui/button-group"<ButtonGroup>
<Button>按钮 1</Button>
<Button>按钮 2</Button>
</ButtonGroup>你可以嵌套按钮组来创建带间距的更复杂布局。
<ButtonGroup>
<ButtonGroup>
<Button>按钮 1</Button>
<Button>按钮 2</Button>
</ButtonGroup>
<ButtonGroup>
<Button>按钮 3</Button>
<Button>按钮 4</Button>
</ButtonGroup>
</ButtonGroup>使用 ButtonGroupSeparator 可创建拆分按钮,经典的下拉菜单模式。
"use client"
import {你也可以用它给输入框加前缀或后缀按钮和文字。
"use client"
import * as React from "react"<ButtonGroup>
<ButtonGroupText>前缀</ButtonGroupText>
<Input placeholder="在这里输入..." />
<Button>按钮</Button>
</ButtonGroup>Input Group
输入组(Input Group)让你在输入框中添加图标、按钮等等。就是你总是需要给输入框加上去的那些小配件。
import {
InputGroup,
InputGroupAddon,
InputGroupInput,
} from "@/components/ui/input-group"<InputGroup>
<InputGroupInput placeholder="搜索..." />
<InputGroupAddon>
<SearchIcon />
</InputGroupAddon>
</InputGroup>带图标的预览如下:
import {
CheckIcon,
CreditCardIcon,你还可以在输入组中添加按钮。
"use client"
import * as React from "react"或者文本、标签、提示气泡……
import {
InputGroup,
InputGroupAddon,它同样支持多行文本输入框(textarea),让你构建真正复杂的组件,有无数控制选项,或者各种提示表单。
import {
IconBrandJavascript,
IconCopy,这里还有几个带旋转器的炫酷例子:
import { LoaderIcon } from "lucide-react"
import {Field
介绍一下 Field,一个专为构建复杂表单设计的组件。这里的抽象非常优雅。
我花了很长时间才做对,但它能兼容所有你的表单库:服务端 Actions,React Hook Form,TanStack Form,任意表单库都支持。
import {
Field,
FieldDescription,
FieldError,
FieldLabel,
} from "@/components/ui/field"下面是一个带输入框的基础表单字段示例:
<Field>
<FieldLabel htmlFor="username">用户名</FieldLabel>
<Input id="username" placeholder="Max Leiter" />
<FieldDescription>
为你的账户选择一个独一无二的用户名。
</FieldDescription>
</Field>import {
Field,
FieldDescription,它兼容所有表单控件。输入框、多行文本框、选择框、复选框、单选钮、开关、滑块,应有尽有。完整示例:
import { Button } from "@/components/ui/button"
import { Checkbox } from "@/components/ui/checkbox"
import {这是复选框字段的演示:
Your Desktop & Documents folders are being synced with iCloud Drive. You can access them from other devices.
import { Checkbox } from "@/components/ui/checkbox"
import {
Field,你可以用 FieldGroup 和 FieldSet 来组合字段,非常适合多部分表单。
<FieldSet>
<FieldLegend />
<FieldGroup>
<Field />
<Field />
</FieldGroup>
</FieldSet>import {
Field,
FieldDescription,让表单响应式很简单。加上 orientation="responsive",它会根据容器宽度自动切换垂直或水平布局。完美。
import { Button } from "@/components/ui/button"
import {
Field,还有更多。用 FieldLabel 包裹字段,创建一个可选的字段组。非常简单,且非常美观。
import {
Field,
FieldContent,Item
这是一个简单的 flex 容器,几乎能容纳任何类型内容。
我做过太多次类似组件了,索性做成了组件。现在我随时使用。用来展示列表项、卡片等内容非常合适。
import {
Item,
ItemContent,
ItemDescription,
ItemMedia,
ItemTitle,
} from "@/components/ui/item"一个基础的项例子:
<Item>
<ItemMedia variant="icon">
<HomeIcon />
</ItemMedia>
<ItemContent>
<ItemTitle>仪表盘</ItemTitle>
<ItemDescription>你的账户和活动概览。</ItemDescription>
</ItemContent>
</Item>A simple item with title and description.
import { BadgeCheckIcon, ChevronRightIcon } from "lucide-react"
import { Button } from "@/components/ui/button"你可以添加图标、头像或图片。
New login detected from unknown device.
import { ShieldAlertIcon } from "lucide-react"
import { Button } from "@/components/ui/button"Last seen 5 months ago
Invite your team to collaborate on this project.
import { Plus } from "lucide-react"
import {下面是用 ItemGroup 组成的多个项:
shadcn@vercel.com
maxleiter@vercel.com
evilrabbit@vercel.com
import * as React from "react"
import { PlusIcon } from "lucide-react"
需要作为链接使用?传入 asChild 属性即可:
<Item asChild>
<a href="/dashboard">
<ItemMedia variant="icon">
<HomeIcon />
</ItemMedia>
<ItemContent>
<ItemTitle>仪表盘</ItemTitle>
<ItemDescription>你的账户和活动概览。</ItemDescription>
</ItemContent>
</a>
</Item>import { ChevronRightIcon, ExternalLinkIcon } from "lucide-react"
import {Empty
最后一个:Empty。用它来展示应用的空状态。
import {
Empty,
EmptyContent,
EmptyDescription,
EmptyMedia,
EmptyTitle,
} from "@/components/ui/empty"用法示例如下:
<Empty>
<EmptyMedia variant="icon">
<InboxIcon />
</EmptyMedia>
<EmptyTitle>无消息</EmptyTitle>
<EmptyDescription>你还没有任何消息。</EmptyDescription>
<EmptyContent>
<Button>发送消息</Button>
</EmptyContent>
</Empty>import { IconFolderCode } from "@tabler/icons-react"
import { ArrowUpRightIcon } from "lucide-react"
你也可以搭配头像使用:
import {
Avatar,
AvatarFallback,或者配合输入组,用于搜索结果、邮箱订阅等场景:
import { SearchIcon } from "lucide-react"
import {就是这样。七个新组件,兼容所有表单库,随时准备进入你的项目。