面包屑 Breadcrumb
显示当前页面在应用信息架构中的层级路径,帮助用户快速感知位置并返回上层页面。
基础用法
最简单的面包屑导航。使用 BreadcrumbList、BreadcrumbItem、BreadcrumbLink、BreadcrumbSeparator 与 BreadcrumbPage 组合层级:
安装与引入
通过 CLI 自动添加组件,或手动复制源码至项目中:
pnpm dlx @wui-design/cli@latest add @wui/breadcrumbpnpm add radix-ui lucide-react clsx tailwind-mergecomponents/ui/breadcrumb.tsximport * as React from "react"
import { ChevronRightIcon, MoreHorizontalIcon } from "lucide-react"
import { Slot } from "radix-ui"
import { cn } from "@/lib/utils"
/** 面包屑导航容器,默认提供可访问名称。 */
function Breadcrumb({ ...props }: React.ComponentProps<"nav">) {
return <nav aria-label="面包屑导航" data-slot="breadcrumb" {...props} />
}
/** 面包屑项目列表。 */
function BreadcrumbList({ className, ...props }: React.ComponentProps<"ol">) {
return (
<ol
data-slot="breadcrumb-list"
className={cn(
"text-muted-foreground m-0 flex list-none flex-wrap items-center gap-1.5 p-0 text-sm sm:gap-2.5",
className
)}
{...props}
/>
)
}
/** 单个面包屑项目。 */
function BreadcrumbItem({ className, ...props }: React.ComponentProps<"li">) {
return (
<li
data-slot="breadcrumb-item"
className={cn(
"m-0 inline-flex min-w-0 items-center gap-1.5 p-0",
className
)}
{...props}
/>
)
}
export interface BreadcrumbLinkProps extends React.ComponentProps<"a"> {
/** 将样式与属性合并到唯一子元素,适合组合路由链接。 */
asChild?: boolean
}
/** 可跳转的面包屑链接。 */
function BreadcrumbLink({
asChild = false,
className,
...props
}: BreadcrumbLinkProps) {
const Comp = asChild ? Slot.Root : "a"
return (
<Comp
data-slot="breadcrumb-link"
className={cn(
"hover:text-foreground focus-visible:ring-ring/40 rounded-sm no-underline outline-none transition-colors duration-200 focus-visible:ring-[3px]",
className
)}
{...props}
/>
)
}
/** 当前页面,自动标记 `aria-current="page"`。 */
function BreadcrumbPage({ className, ...props }: React.ComponentProps<"span">) {
return (
<span
aria-current="page"
data-slot="breadcrumb-page"
className={cn("text-foreground font-medium", className)}
{...props}
/>
)
}
/** 相邻面包屑之间的装饰性分隔符。 */
function BreadcrumbSeparator({
children,
className,
...props
}: React.ComponentProps<"li">) {
return (
<li
aria-hidden="true"
data-slot="breadcrumb-separator"
role="presentation"
className={cn("m-0 p-0 [&>svg]:size-3.5", className)}
{...props}
>
{children ?? <ChevronRightIcon />}
</li>
)
}
/** 表示中间路径被折叠的省略项。 */
function BreadcrumbEllipsis({
className,
...props
}: React.ComponentProps<"span">) {
return (
<span
data-slot="breadcrumb-ellipsis"
className={cn("flex size-7 items-center justify-center", className)}
{...props}
>
<MoreHorizontalIcon aria-hidden="true" className="size-4" />
<span className="sr-only">更多层级</span>
</span>
)
}
export {
Breadcrumb,
BreadcrumbEllipsis,
BreadcrumbItem,
BreadcrumbLink,
BreadcrumbList,
BreadcrumbPage,
BreadcrumbSeparator,
}
属性 Props
Breadcrumb (根组件)
继承原生 <nav> 元素的全部 HTML 属性:
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| aria-label | string | "面包屑导航" | 用于屏幕阅读器识别导航地标的可访问名称。 |
| className | string | — | 应用于外层 nav 元素的额外 CSS 类名。 |
BreadcrumbLink
继承原生 <a> 元素的全部 HTML 属性:
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| href | string | — | 目标跳转链接地址。 |
| asChild | boolean | false | 启用后将样式与属性合并到唯一的子元素(如 Next.js `<Link>`)。 |
| className | string | — | 应用于链接元素的额外 CSS 类名。 |
BreadcrumbPage
当前所在页面的文本容器,自动附带 aria-current="page" 语义:
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| children | React.ReactNode | — | 当前页面的标题或内容展示。 |
| className | string | — | 应用于当前页标签的额外 CSS 类名。 |
BreadcrumbSeparator
用于相邻面包屑项目之间的装饰性分隔符:
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| children | React.ReactNode | <ChevronRightIcon /> | 自定义分隔符图标或字符。若不传则默认使用右箭头图标。 |
| className | string | — | 应用于分隔符 `<li>` 元素的额外 CSS 类名。 |
BreadcrumbEllipsis
用于表示中间长路径被折叠的省略号占位符:
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| className | string | — | 应用于省略号图标容器的额外 CSS 类名。 |
事件 Events
面包屑各子元素均继承原生 HTML 事件:
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| onClick | (event: React.MouseEvent<HTMLAnchorElement>) => void | — | 用户点击可跳转链接项时触发,可用于 SPA 客户端路由拦截或埋点追踪。 |
| onFocus | (event: React.FocusEvent<HTMLAnchorElement>) => void | — | 链接项通过键盘 Tab 或鼠标聚焦时触发。 |
| onKeyDown | (event: React.KeyboardEvent<HTMLAnchorElement>) => void | — | 在链接项聚焦状态下按下按键时触发。 |
使用场景与设计规范
Breadcrumb 用于表达有层级关系的纵深路径结构(例如:首页 > 控制台 > 集群管理 > 节点详情):
- 辅助导航而非主导航:面包屑旨在辅助用户了解“我在哪里”以及“如何返回上级”,不能代替顶部 Navbar 或左侧 Sidebar 等核心主导航系统。
- 当前页不可点击:末尾的当前页面项必须使用
BreadcrumbPage(纯文本容器并内置aria-current="page"),不应赋予链接跳转属性,避免无意义的页面重载。 - 层级过深时合理折叠:当路径层级超过 4~5 层或在移动端等小屏幕上时,应使用
BreadcrumbEllipsis折叠中间层级,或配合DropdownMenu提供便捷跳转。 - 路径命名与页面标题一致:面包屑中的每一级文案应与对应目标页面的实际主标题保持一致,降低用户的认知负荷。
场景示例
搭配图标指示
在面包屑各级节点前加入上下文图标(如首页图标、文件夹图标、配置图标),提高视觉识别效率:
自定义分隔符
支持通过在 <BreadcrumbSeparator> 内部传入自定义图标(如斜杠 <SlashIcon>、推进箭头 <ArrowRightIcon>)或文本字符(如 •):
折叠长路径与下拉菜单
对于深层级文件目录或多层资源拓扑,将省略号与 DropdownMenu 结合,既节省屏幕横向宽度,又保留快速跨级导航的能力:
简单折叠占位
使用 BreadcrumbEllipsis 纯展示性折叠路径:
路径进出动效与展开折叠
在文件浏览器等路径频繁变化的场景中,可以用 motion.create 包装 BreadcrumbItem 与 BreadcrumbSeparator,配合 AnimatePresence 让新层级从左侧滑入、返回上级时多余层级淡出,其余项平滑补位。层级超过 4 级时中间路径折叠为省略号按钮,点击后原地展开:
与框架路由组合 (Next.js Link)
启用 asChild 属性,组件会自动将类名与可访问属性合并至第三方路由链接上,避免生成无效嵌套标签:
import Link from "next/link"
import { BreadcrumbItem, BreadcrumbLink } from "@/registry/ui/breadcrumb"
<BreadcrumbItem>
<BreadcrumbLink asChild>
<Link href="/dashboard/projects">项目列表</Link>
</BreadcrumbLink>
</BreadcrumbItem>无障碍与交互 Accessibility
- 语义地标 Landmark:根组件自动渲染为
<nav aria-label="面包屑导航">,屏幕阅读器用户可通过快捷键直接跳转至该导航地标。 - 列表结构语义:内部采用
<ol>与<li>的有序列表结构,精确传达出页面从上至下的父子层级顺序。 - 当前页语义标注:
BreadcrumbPage自动携带aria-current="page"属性,盲文与语音读屏器会自动播报“当前页面”。 - 装饰元素隔离:
BreadcrumbSeparator内置aria-hidden="true"和role="presentation";BreadcrumbEllipsis仅隐藏图标,保留sr-only的「更多层级」文案,放入按钮或下拉触发器时可被正确播报(也可在触发器上用aria-label覆盖)。 - 键盘焦点轮廓:
BreadcrumbLink具备高对比度的 Focus Ring 焦点态轮廓,支持通过 Tab 键快速顺序遍历所有有效链接。