106k
New

Changelog

RSS

Latest updates and announcements.

2026年1月 - 内联起始和结束样式

我们更新了 Base UI 组件的样式以支持 inline-startinline-end 侧值。以下组件现已支持这些值:

  • Tooltip(工具提示)
  • Popover(弹出框)
  • Combobox(组合框)
  • Context Menu(上下文菜单)
  • Dropdown Menu(下拉菜单)
  • Hover Card(悬停卡片)
  • Menubar(菜单栏)
  • Select(选择框)

变更内容

我们添加了新的 Tailwind 类以支持逻辑侧值:

<PopoverPrimitive.Popup
  className={cn(
    "... data-[side=bottom]:slide-in-from-top-2
    data-[side=left]:slide-in-from-right-2
    data-[side=right]:slide-in-from-left-2
    data-[side=top]:slide-in-from-bottom-2
+   data-[side=inline-start]:slide-in-from-right-2
+   data-[side=inline-end]:slide-in-from-left-2 ...",
    className
  )}
/>

使用示例

<Popover>
  <PopoverTrigger>Open</PopoverTrigger>
  <PopoverContent side="inline-start">
    {/* 在 LTR 中向左打开,在 RTL 中向右打开 */}
  </PopoverContent>
</Popover>

LLM 提示

通过运行以下提示,要求你的 LLM 更新你的组件:

Add inline-start and inline-end support to my shadcn/ui components. Add the following Tailwind classes to each component:
 
| File | Component | Add Classes |
|------|-----------|-------------|
| tooltip.tsx | TooltipContent | `data-[side=inline-start]:slide-in-from-right-2 data-[side=inline-end]:slide-in-from-left-2` |
| tooltip.tsx | TooltipArrow | `data-[side=inline-start]:top-1/2! data-[side=inline-start]:-right-1 data-[side=inline-start]:-translate-y-1/2
data-[side=inline-end]:top-1/2! data-[side=inline-end]:-left-1 data-[side=inline-end]:-translate-y-1/2` |
| popover.tsx | PopoverContent | `data-[side=inline-start]:slide-in-from-right-2 data-[side=inline-end]:slide-in-from-left-2` |
| hover-card.tsx | HoverCardContent | `data-[side=inline-start]:slide-in-from-right-2 data-[side=inline-end]:slide-in-from-left-2` |
| select.tsx | SelectContent | `data-[side=inline-start]:slide-in-from-right-2 data-[side=inline-end]:slide-in-from-left-2
data-[align-trigger=true]:animate-none` and add `data-align-trigger={alignItemWithTrigger}` attribute |
| combobox.tsx | ComboboxContent | `data-[side=inline-start]:slide-in-from-right-2 data-[side=inline-end]:slide-in-from-left-2` |
| dropdown-menu.tsx | DropdownMenuContent | `data-[side=inline-start]:slide-in-from-right-2 data-[side=inline-end]:slide-in-from-left-2` |
| context-menu.tsx | ContextMenuContent | `data-[side=inline-start]:slide-in-from-right-2 data-[side=inline-end]:slide-in-from-left-2` |
| menubar.tsx | MenubarContent | `data-[side=inline-start]:slide-in-from-right-2 data-[side=inline-end]:slide-in-from-left-2` |
 
Add these classes next to the existing `data-[side=top]`, `data-[side=bottom]`, `data-[side=left]`, `data-[side=right]` classes.

2026年1月 - Base UI 文档

我们已发布了 Base UI 组件的完整文档。

今年12月我们推出了 npx shadcn create,新增了选择 Radix 或 Base UI 作为组件库的功能。今天,我们为所有 Base UI 组件发布了完整的文档。

新特性

  • 完整的 Base UI 文档 —— 每个组件现在都有针对 Base UI 的专门文档,涵盖用法、属性和示例。
  • 重建示例 —— 所有组件示例都为 Radix 和 Base UI 重新构建。可切换查看两者在实现上的差异。
  • 并列对比 —— 文档方便地对比两个库中组件的工作方式。

相同抽象,不同原语

目标不变:无论选用哪个原语库,都提供一致的 API。组件外观和行为相同,唯独底层实现不同。

// 无论使用 Radix 还是 Base UI,工作方式都相同。
import { Dialog, DialogContent, DialogTrigger } from "@/components/ui/dialog"

如果你正在启动新项目,运行 npx shadcn create 并选择你偏好的库,CLI 会完成剩余工作。

试试 shadcn/create

2025年12月 - npx shadcn create

从最初的提交开始,shadcn/ui 的目标就是让它可定制化。

我们的想法是为你提供坚实的默认值、间距、颜色标记、动画、无障碍支持,然后让你从这里开始。调整代码。添加新组件。更改颜色。构建你自己的版本。

但在某个阶段,所有应用开始看起来都一样了。我猜默认值太_好_了。我的错。

今天,我们要改变这一点:npx shadcn create

自定义一切。选择你的组件库、图标、基础颜色、主题、字体,创建你专属版本的 shadcn/ui。

我们从5种全新视觉风格开始,旨在帮助你的 UI 真正感觉像_你的_UI。

  • Vega – 经典的 shadcn/ui 外观。
  • Nova – 减少内边距和外边距,适合紧凑布局。
  • Maia – 柔和圆润,间距宽松。
  • Lyra – 方正且锐利。与等宽字体搭配良好。
  • Mira – 紧凑。专为密集界面设计。

这不仅仅是主题切换

你的配置不仅仅改变颜色,它还会重写组件代码以匹配你的设置。字体、间距、结构,甚至你使用的库,所有一切都根据你的喜好自适应。

全新的 CLI 帮你搞定一切。

从一个组件库开始。选择 Radix 或 Base UI。

我们为 Base UI 重新构建了每个组件,保持相同的抽象层。 它们与现有组件完全兼容,甚至包括从远程注册表拉取的组件。

当你拉取组件时,我们会自动检测你使用的库,并应用正确的转换。

是时候构建一个看起来与众不同的作品了。

现已支持 Next.js、Vite、TanStack Start 和 v0。

开始使用

2025年10月 - 注册表目录

我们刚刚发布了注册表目录:一个您可以浏览并拉取代码和组件的代码注册表列表。

https://ui.shadcn.com/docs/directory

内置于 CLI 中,无需配置。

2025年10月 - 新组件

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

这些组件兼容所有组件库,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 {

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