106k
New

2025年10月 - 新组件

旋转器(Spinner)、键盘按键(Kbd)、按钮组(Button Group)、输入组(Input Group)、表单字段(Field)、项(Item)和空状态组件(Empty)。

这轮新组件,我关注了我们每天都在做的事情,那些无趣而重复构建的基础内容,并做了真正可重用的抽象组件。

这些组件兼容所有组件库,Radix、Base UI、React Aria,随你喜欢。复制粘贴直接用到你的项目里。

Spinner

先从最简单的开始:SpinnerKbd。非常基础,我们都知道它们是干什么的。

下面是如何渲染一个旋转器:

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>
Ctrl+B
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,

你还可以在输入组中添加按钮。

https://
"use client"

import * as React from "react"

或者文本、标签、提示气泡……

$
USD
https://
.com
@company.com
120 characters left
import {
  InputGroup,
  InputGroupAddon,

它同样支持多行文本输入框(textarea),让你构建真正复杂的组件,有无数控制选项,或者各种提示表单。

Line 1, Column 1
script.js
import {
  IconBrandJavascript,
  IconCopy,

这里还有几个带旋转器的炫酷例子:

Saving...
Please wait...
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>

Choose a unique username for your account.

Must be at least 8 characters long.

import {
  Field,
  FieldDescription,

它兼容所有表单控件。输入框、多行文本框、选择框、复选框、单选钮、开关、滑块,应有尽有。完整示例:

Payment Method

All transactions are secure and encrypted

Enter your 16-digit card number

Billing Address

The billing address associated with your payment method

import { Button } from "@/components/ui/button"
import { Checkbox } from "@/components/ui/checkbox"
import {

这是复选框字段的演示:

Show these items on the desktop

Select the items you want to show on the desktop.

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,

你可以用 FieldGroupFieldSet 来组合字段,非常适合多部分表单。

<FieldSet>
  <FieldLegend />
  <FieldGroup>
    <Field />
    <Field />
  </FieldGroup>
</FieldSet>
Address Information

We need your address to deliver your order.

import {
  Field,
  FieldDescription,

让表单响应式很简单。加上 orientation="responsive",它会根据容器宽度自动切换垂直或水平布局。完美。

Profile

Fill in your profile information.

Provide your full name for identification

You can write your message here. Keep it short, preferably under 100 characters.

import { Button } from "@/components/ui/button"
import {
  Field,

还有更多。用 FieldLabel 包裹字段,创建一个可选的字段组。非常简单,且非常美观。

Select the compute environment for your cluster.

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>
Basic Item

A simple item with title and description.

Your profile has been verified.
import { BadgeCheckIcon, ChevronRightIcon } from "lucide-react"

import { Button } from "@/components/ui/button"

你可以添加图标、头像或图片。

Security Alert

New login detected from unknown device.

import { ShieldAlertIcon } from "lucide-react"

import { Button } from "@/components/ui/button"
ER
Evil Rabbit

Last seen 5 months ago

ER
No Team Members

Invite your team to collaborate on this project.

import { Plus } from "lucide-react"

import {

下面是用 ItemGroup 组成的多个项:

s
shadcn

shadcn@vercel.com

m
maxleiter

maxleiter@vercel.com

e
evilrabbit

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>
No Projects Yet
You haven't created any projects yet. Get started by creating your first project.
Learn More
import { IconFolderCode } from "@tabler/icons-react"
import { ArrowUpRightIcon } from "lucide-react"

你也可以搭配头像使用:

LR
User Offline
This user is currently offline. You can leave a message to notify them or try again later.
import {
  Avatar,
  AvatarFallback,

或者配合输入组,用于搜索结果、邮箱订阅等场景:

404 - Not Found
The page you're looking for doesn't exist. Try searching for what you need below.
/
Need help? Contact support
import { SearchIcon } from "lucide-react"

import {

就是这样。七个新组件,兼容所有表单库,随时准备进入你的项目。