<Sidebar.Provider defaultOpen>
<Sidebar>
<Sidebar.Content>
<Sidebar.Group>
<Sidebar.GroupLabel>Overview</Sidebar.GroupLabel>
<Sidebar.Menu>
<Sidebar.MenuButton icon={HouseIcon} active>Home</Sidebar.MenuButton>
<Sidebar.MenuButton icon={GlobeIcon}>Domains</Sidebar.MenuButton>
</Sidebar.Menu>
</Sidebar.Group>
</Sidebar.Content>
</Sidebar>
</Sidebar.Provider>安装
桶式导出
import { Sidebar } from "@cloudflare/kumo";细粒度导入
import { Sidebar } from "@cloudflare/kumo/components/sidebar";用法
至少需要 Provider、Sidebar、Content(可滚动区域)、Menu 和MenuButton。 添加 Header /Footer 可将内容固定到滚动区域上方或下方。 使用 Group +GroupLabel 组织分区。
import { Sidebar } from "@cloudflare/kumo";
import { HouseIcon, CodeIcon, GearIcon } from "@phosphor-icons/react";
function AppLayout({ children }) {
return (
<Sidebar.Provider defaultOpen>
<Sidebar>
<Sidebar.Content>
<Sidebar.Group>
<Sidebar.GroupLabel>Navigation</Sidebar.GroupLabel>
<Sidebar.Menu>
<Sidebar.MenuButton icon={HouseIcon} active>Home</Sidebar.MenuButton>
{/* MenuItem only needed to wrap Collapsible */}
<Sidebar.MenuItem>
<Sidebar.Collapsible>
<Sidebar.CollapsibleTrigger
render={
<Sidebar.MenuButton icon={CodeIcon}>
Compute <Sidebar.MenuChevron />
</Sidebar.MenuButton>
}
/>
<Sidebar.CollapsibleContent>
<Sidebar.MenuSub>
<Sidebar.MenuSubButton>Workers</Sidebar.MenuSubButton>
</Sidebar.MenuSub>
</Sidebar.CollapsibleContent>
</Sidebar.Collapsible>
</Sidebar.MenuItem>
</Sidebar.Menu>
</Sidebar.Group>
</Sidebar.Content>
<Sidebar.Footer>
<Sidebar.Trigger />
</Sidebar.Footer>
</Sidebar>
<div className="flex-1">{children}</div>
</Sidebar.Provider>
);
}示例
基础
最小可用的侧边栏:只有分组、菜单按钮与可折叠子菜单,没有页头或页脚。MenuButton 和 MenuSubButton 会自动包裹在 <li> 中 — 无需 MenuItem / MenuSubItem。
<Sidebar.Provider defaultOpen>
<Sidebar>
<Sidebar.Content>
<Sidebar.Group>
<Sidebar.GroupLabel>Overview</Sidebar.GroupLabel>
<Sidebar.Menu>
<Sidebar.MenuButton icon={HouseIcon} active>Home</Sidebar.MenuButton>
<Sidebar.MenuButton icon={ChartBarIcon}>Analytics</Sidebar.MenuButton>
</Sidebar.Menu>
</Sidebar.Group>
</Sidebar.Content>
</Sidebar>
</Sidebar.Provider>切换与折叠状态
在页脚使用 Sidebar.Trigger,或以编程方式调用 useSidebar().toggleSidebar。折叠时传入 tooltip,可在悬停时显示标签。
<Sidebar.MenuButton icon={HouseIcon} tooltip="Home" active>
Home
</Sidebar.MenuButton>
<Sidebar.Footer>
<Sidebar.Trigger />
</Sidebar.Footer>
// Or programmatically:
const { toggleSidebar } = useSidebar();加载中
Sidebar.Loading 在路由与权限解析期间,以导航项目形状的骨架行替代导航内容。折叠时只保留图标方块。遵循 reduced-motion 设置。
<Sidebar>
<Sidebar.Header>…</Sidebar.Header>
{isLoading ? (
<Sidebar.Loading />
) : (
<Sidebar.Content>…</Sidebar.Content>
)}
<Sidebar.Footer>…</Sidebar.Footer>
</Sidebar>可调整大小
拖拽边缘即可调整大小。拖到低于 minWidth 会折叠;从折叠状态向外拖拽会展开。 调整手柄支持键盘操作:可用方向键、Home 和 End。
<Sidebar.Provider defaultOpen resizable defaultWidth={240} minWidth={180} maxWidth={400}>
<Sidebar>
<Sidebar.Content>...</Sidebar.Content>
<Sidebar.ResizeHandle />
</Sidebar>
</Sidebar.Provider>右侧
使用 side="right" 可将侧边栏放在右侧边缘。在 DOM 中应将 <Sidebar> 放在 <main> 之前。
<Sidebar.Provider defaultOpen side="right">
<main className="flex-1">...</main>
<Sidebar>
<Sidebar.Content>
<Sidebar.Group>
<Sidebar.GroupLabel>Details</Sidebar.GroupLabel>
<Sidebar.Menu>
<Sidebar.MenuButton icon={GearIcon} active>Properties</Sidebar.MenuButton>
<Sidebar.MenuButton icon={ChartBarIcon}>Metrics</Sidebar.MenuButton>
</Sidebar.Menu>
</Sidebar.Group>
</Sidebar.Content>
</Sidebar>
</Sidebar.Provider>悬停展开
在 Provider 上设置 peekable。侧边栏折叠时, 将鼠标悬停或聚焦到它上面会临时展开;移开后又会折叠回去。 悬停展开期间,data-state 属性会变为 "peeking"。
<Sidebar.Provider defaultOpen peekable>
<Sidebar>
<Sidebar.Content>...</Sidebar.Content>
<Sidebar.Footer>
<Sidebar.Trigger />
</Sidebar.Footer>
</Sidebar>
</Sidebar.Provider>
// Read peeking state:
const { state, isPeeking } = useSidebar();
// state: "expanded" | "collapsed" | "peeking"自动滚动
在较长的可折叠分区上使用 autoScrollOnOpen,可让新展开的内容保持在视线内。 当可滚动侧边栏底部附近的分组展开到可见区域之外时,这一功能很有用。
<Sidebar.Collapsible autoScrollOnOpen>
<Sidebar.CollapsibleTrigger
render={
<Sidebar.MenuButton icon={CodeIcon}>
Workers <Sidebar.MenuChevron />
</Sidebar.MenuButton>
}
/>
<Sidebar.CollapsibleContent>
<Sidebar.MenuSub>...</Sidebar.MenuSub>
</Sidebar.CollapsibleContent>
</Sidebar.Collapsible>过渡完成
当某些工作必须等待侧边栏或可折叠分区的过渡结束后才能进行(如测量布局或滚动新展开的内容)时,请使用 onOpenChangeComplete。回调会收到最终的打开状态,并且在 reduced motion 禁用过渡时也会执行。当侧边栏或移动端抽屉显示或隐藏已打开的分区时,Sidebar.Collapsible 也会触发完成回调,因此回调始终与用户所见一致。
const [completion, setCompletion] = useState("");
<Sidebar.Provider
defaultOpen
onOpenChangeComplete={(open) => {
setCompletion("Sidebar " + (open ? "opened." : "collapsed."));
}}
>
<Sidebar>
<Sidebar.Content>
<Sidebar.Menu>
<Sidebar.MenuItem>
<Sidebar.Collapsible
onOpenChangeComplete={(open) => {
setCompletion(
"Compute section " + (open ? "opened." : "collapsed."),
);
}}
>
<Sidebar.CollapsibleTrigger render={<Sidebar.MenuButton>Compute</Sidebar.MenuButton>} />
<Sidebar.CollapsibleContent>...</Sidebar.CollapsibleContent>
</Sidebar.Collapsible>
</Sidebar.MenuItem>
</Sidebar.Menu>
</Sidebar.Content>
<Sidebar.Footer><Sidebar.Trigger /></Sidebar.Footer>
</Sidebar>
</Sidebar.Provider>滚动到指定项目
用 itemId 标记导航项目,然后调用 useSidebar().scrollToItem(id, options) 将其滚动到视线内。当项目已完全可见时,可用 scrollItemIntoView(id, options) 保持当前位置不变。align 可取 "start"、"center"、"end" 或 "auto"(默认值,已可见时不做任何操作)。behavior 默认为 "auto"(即时),这样跨应用落地时不会在进入时播放动画;应用内的「跳转到分区」流程请传入 "smooth"。遵循 prefers-reduced-motion 设置。与 Sidebar.SlidingViews 配合正常 — 项目来自每个 provider 各自的注册表,而不是通过 DOM 查询解析。
itemId 在两种用法下都有效:直接用在 Sidebar.MenuButton 上(常见情况,会自动包裹在 <li> 中),或当你在 Sidebar.MenuItem 中包裹 Collapsible 时用在其上。即使把 itemId 放在嵌套于 MenuItem 之内的 MenuButton 上,也仍然有效 — 按钮本身会成为滚动目标。
<Sidebar.MenuButton itemId="zero-trust" href="/zt">
Zero Trust
</Sidebar.MenuButton>
// elsewhere:
const { scrollToItem } = useSidebar();
scrollToItem("zero-trust", { align: "center", behavior: "smooth" });滑动视图
使用 Sidebar.SlidingViews 和 Sidebar.SlidingView可在不同导航界面之间实现带动画的水平过渡(例如账户 ↔ 区域)。 非活动视图会自动标记 aria-hidden 与 inert。 动画遵循 prefers-reduced-motion 设置。
const [surface, setSurface] = useState("account");
<Sidebar.SlidingViews activeKey={surface} direction="left">
<Sidebar.SlidingView value="account">
<Sidebar.Content>...account nav...</Sidebar.Content>
</Sidebar.SlidingView>
<Sidebar.SlidingView value="zone">
<Sidebar.Content>...zone nav...</Sidebar.Content>
</Sidebar.SlidingView>
</Sidebar.SlidingViews>完整示例
覆盖所有子组件的完整示例:带账户切换器的页头、带标签的分组、含嵌套可展开项的可折叠分区、徽章、滑动视图和页脚触发器。
<Sidebar>
<Sidebar.Header>
<AccountSwitcher />
</Sidebar.Header>
<Sidebar.Content>
<Sidebar.Group>
<Sidebar.Menu>
<Sidebar.MenuButton icon={HouseIcon} active>Home</Sidebar.MenuButton>
</Sidebar.Menu>
</Sidebar.Group>
<Sidebar.Group>
<Sidebar.GroupLabel>Build</Sidebar.GroupLabel>
<Sidebar.Menu>
<Sidebar.MenuItem>
<Sidebar.Collapsible defaultOpen>
<Sidebar.CollapsibleTrigger
render={
<Sidebar.MenuButton icon={CodeIcon}>
Compute <Sidebar.MenuChevron />
</Sidebar.MenuButton>
}
/>
<Sidebar.CollapsibleContent>
<Sidebar.MenuSub>
<Sidebar.MenuSubButton>
Containers <Sidebar.MenuBadge>Beta</Sidebar.MenuBadge>
</Sidebar.MenuSubButton>
</Sidebar.MenuSub>
</Sidebar.CollapsibleContent>
</Sidebar.Collapsible>
</Sidebar.MenuItem>
</Sidebar.Menu>
</Sidebar.Group>
</Sidebar.Content>
<Sidebar.Footer>
<Sidebar.Trigger />
</Sidebar.Footer>
</Sidebar>移动端
在窄视口下,侧边栏以导航抽屉的形式渲染。使用 mobileBreakpoint 控制阈值。 抽屉在关闭时使用 inert 与 aria-hidden,打开时将焦点移入,并支持按 Escape 关闭。 此演示通过一个很大的断点值强制进入移动端模式。
<Sidebar.Provider mobileBreakpoint={9999}>
<Sidebar>
<Sidebar.Content>...</Sidebar.Content>
</Sidebar>
</Sidebar.Provider>移动端全屏
传入 fullScreenOnMobile 可让抽屉覆盖整个视口,而不在页面边缘留下一小条可见区域。 导航项目会获得更舒适的触控目标,同时由于面板背后不再显示任何内容,背景遮罩会被隐藏。 在页头内添加 Sidebar.Close,即可在导航内部关闭面板。 与页面页头中的面包屑搭配使用,这样导航关闭后当前路由仍然可见。
<Sidebar.Provider mobileBreakpoint={9999}>
<Sidebar fullScreenOnMobile>
<Sidebar.Header>
<Sidebar.Close />
</Sidebar.Header>
<Sidebar.Content>...</Sidebar.Content>
</Sidebar>
<header>
<Sidebar.Trigger />
<Breadcrumbs size="sm">
<Breadcrumbs.Link href="/">Company</Breadcrumbs.Link>
<Breadcrumbs.Separator />
<Breadcrumbs.Current>Analytics</Breadcrumbs.Current>
</Breadcrumbs>
</header>
</Sidebar.Provider>API 参考
Sidebar
侧边栏主容器。在桌面端渲染为 <aside>,在移动端渲染为导航抽屉。
| Prop | Type | Default | Description |
|---|---|---|---|
| defaultOpen | boolean | - | 非受控模式下的初始打开状态。 |
| open | boolean | - | 受控的打开状态。 |
| variant | "sidebar" | "floating" | "inset" | "sidebar" | 侧边栏布局变体。 |
| side | "left" | "right" | "left" | 侧边栏位于哪一侧。 |
| collapsible | "icon" | "offcanvas" | "none" | "icon" | - |
| resizable | boolean | - | 在侧边栏边缘启用拖动调整大小。 |
| defaultWidth | number | - | 可调整大小时的初始像素宽度。 |
| minWidth | number | - | 调整大小时的最小宽度(像素)。 |
| maxWidth | number | - | 调整大小时的最大宽度(像素)。 |
| contained | boolean | - | 当 |
| peekable | boolean | - | 当 |
| animationDuration | number | - | 侧边栏展开/折叠动画的持续时间(毫秒)。 |
| mobileBreakpoint | number | - | 视口宽度(以像素为单位),低于此宽度时侧边栏渲染为移动端对话框面板,而非桌面端侧边栏。 |
| children | ReactNode | - | 内容——通常是 |
| className | string | - | 包装 div 的额外 CSS 类。 |
Sidebar.Provider
管理展开/折叠状态与移动端检测的上下文 Provider。
| Prop | Type | Default | Description |
|---|---|---|---|
| defaultOpen | boolean | - | 非受控模式下的初始打开状态。 |
| open | boolean | - | 受控的打开状态。 |
| variant | SidebarVariant | - | 侧边栏布局变体。 |
| side | SidebarSide | - | 侧边栏位于哪一侧。 |
| collapsible | "icon" | "offcanvas" | "none" | - | - |
| resizable | boolean | - | 在侧边栏边缘启用拖动调整大小。 |
| defaultWidth | number | - | 可调整大小时的初始像素宽度。 |
| minWidth | number | - | 调整大小时的最小宽度(像素)。 |
| maxWidth | number | - | 调整大小时的最大宽度(像素)。 |
| contained | boolean | - | 当 |
| peekable | boolean | - | 当 |
| animationDuration | number | - | 侧边栏展开/折叠动画的持续时间(毫秒)。 |
| mobileBreakpoint | number | - | 视口宽度(以像素为单位),低于此宽度时侧边栏渲染为移动端对话框面板,而非桌面端侧边栏。 |
| children* | ReactNode | - | 内容——通常是 |
| className | string | - | 包装 div 的额外 CSS 类。 |
Sidebar.Content
可滚动的中间区域(flex-1 overflow-y-auto)。使用 Header / Footer 可将内容固定到该滚动区域的上方或下方。
Sidebar.MenuButton
主要的交互元素。支持图标、激活状态、链接,以及折叠时的自动 tooltip。 会自动包裹在 <li> 中 — 除非需要包裹 Collapsible,否则无需 MenuItem 包装。
| Prop | Type | Default | Description |
|---|---|---|---|
| icon | React.ComponentType<{ className?: string }> | React.ReactNode | - | - |
| active | boolean | - | - |
| size | SidebarMenuButtonSize | - | 按钮尺寸。 - |
| href | string | - | - |
| target | React.HTMLAttributeAnchorTarget | - | 链接目标——仅在提供 |
| tooltip | string | - | - |
| itemId | string | - |
|
| className | string | - | - |
| children | ReactNode | - | - |
Sidebar.MenuSubButton
子菜单内用于嵌套导航的按钮。 会自动包裹在 <li> 中 — 无需 MenuSubItem 包装。
| Prop | Type | Default | Description |
|---|---|---|---|
| active | boolean | - | 将此子项标记为当前活动/已选中。 |
| href | string | - | 导航 URL。设置后,通过 |
| target | React.HTMLAttributeAnchorTarget | - | 链接目标——仅在提供 |