侧边栏
一个可组合、支持主题定制和自定义的侧边栏组件。
侧边栏是构建起来最复杂的组件之一。它们是任何应用程序的核心,通常包含许多活动部件。
我不喜欢构建侧边栏。所以我构建了 30 多个。各种配置都有。然后我将核心组件提取到 Sidebar*.vue 中。
我们现在有了一个坚实的基础来构建。可组合。支持主题。可定制。
安装
安装此组件
pnpm dlx shadcn-vue@latest add sidebar
将以下颜色添加到您的 CSS 文件中
上述命令应为您安装颜色。如果没有,请在您的 CSS 文件中复制并粘贴以下内容。
@layer base {
:root {
--sidebar-background: 0 0% 98%;
--sidebar-foreground: 240 5.3% 26.1%;
--sidebar-primary: 240 5.9% 10%;
--sidebar-primary-foreground: 0 0% 98%;
--sidebar-accent: 240 4.8% 95.9%;
--sidebar-accent-foreground: 240 5.9% 10%;
--sidebar-border: 220 13% 91%;
--sidebar-ring: 217.2 91.2% 59.8%;
}
.dark {
--sidebar-background: 240 5.9% 10%;
--sidebar-foreground: 240 4.8% 95.9%;
--sidebar-primary: 224.3 76.3% 48%;
--sidebar-primary-foreground: 0 0% 100%;
--sidebar-accent: 240 3.7% 15.9%;
--sidebar-accent-foreground: 240 4.8% 95.9%;
--sidebar-border: 240 3.7% 15.9%;
--sidebar-ring: 217.2 91.2% 59.8%;
}
}结构
一个 Sidebar 组件由以下部分组成:
SidebarProvider- 处理可折叠状态。Sidebar- 侧边栏容器。SidebarHeader和 SidebarFooter - 固定在侧边栏的顶部和底部SidebarContent- 可滚动内容。SidebarGroup- SidebarContent 内的部分。SidebarTrigger- 侧边栏的触发器

用法
<script setup lang="ts">
import AppSidebar from '@/components/AppSidebar.vue'
import { SidebarProvider, SidebarTrigger } from '@/components/ui/sidebar'
</script>
<template>
<SidebarProvider>
<AppSidebar />
<main>
<SidebarTrigger />
<RouterView />
</main>
</SidebarProvider>
</template><script setup lang="ts">
import {
Sidebar,
SidebarContent,
SidebarFooter,
SidebarGroup,
SidebarHeader,
} from '@/components/ui/sidebar'
</script>
<template>
<Sidebar>
<SidebarHeader />
<SidebarContent>
<SidebarGroup />
<SidebarGroup />
</SidebarContent>
<SidebarFooter />
</Sidebar>
</template>您的第一个侧边栏
让我们从最基本的侧边栏开始:一个带有菜单的可折叠侧边栏。
在应用程序的根目录添加 SidebarProvider 和 SidebarTrigger。
<script setup lang="ts">
import { SidebarProvider, SidebarTrigger } from "@/components/ui/sidebar";
import AppSidebar from "@/components/AppSidebar.vue";
</script>
<template>
<SidebarProvider>
<AppSidebar />
<main>
<SidebarTrigger />
<slot />
</main>
</SidebarProvider>
</template>在 @/components/AppSidebar.vue 创建一个新的侧边栏组件。
<script setup lang="ts">
import { Sidebar, SidebarContent } from "@/components/ui/sidebar";
</script>
<template>
<Sidebar>
<SidebarContent />
</Sidebar>
</template>现在,让我们向侧边栏添加一个 SidebarMenu
我们将在 SidebarGroup 中使用 SidebarMenu 组件。
<script setup lang="ts">
import { Calendar, Home, Inbox, Search, Settings } from "lucide-vue-next"
import {
Sidebar,
SidebarContent,
SidebarGroup,
SidebarGroupContent,
SidebarGroupLabel,
SidebarMenu,
SidebarMenuButton,
SidebarMenuItem,
} from "@/components/ui/sidebar"
// 菜单项。
const items = [
{
title: "首页",
url: "#",
icon: Home,
},
{
title: "收件箱",
url: "#",
icon: Inbox,
},
{
title: "日历",
url: "#",
icon: Calendar,
},
{
title: "搜索",
url: "#",
icon: Search,
},
{
title: "设置",
url: "#",
icon: Settings,
},
];
</script>
<template>
<Sidebar>
<SidebarContent>
<SidebarGroup>
<SidebarGroupLabel>应用程序</SidebarGroupLabel>
<SidebarGroupContent>
<SidebarMenu>
<SidebarMenuItem v-for="item in items" :key="item.title">
<SidebarMenuButton asChild>
<a :href="item.url">
<component :is="item.icon" />
<span>{{item.title}}</span>
</a>
</SidebarMenuButton>
</SidebarMenuItem>
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
</SidebarContent>
</Sidebar>
</template>您已创建了第一个侧边栏
组件
Sidebar*.vue 文件中的组件被设计为可组合的,即您通过将提供的组件组合在一起来构建侧边栏。它们也能很好地与其他 shadcn-vue 组件(如 DropdownMenu、Collapsible、Dialog 等)组合使用。
如果您需要更改 Sidebar*.vue 文件中的代码,我们鼓励您这样做。代码是您的。使用提供的组件作为起点来构建您自己的组件。
在接下来的部分中,我们将介绍每个组件及其使用方法。
SidebarProvider
SidebarProvider 组件用于向 Sidebar 组件提供侧边栏上下文。您应始终将您的应用程序包装在 SidebarProvider 组件中。
Props
| 名称 | 类型 | 描述 |
|---|---|---|
defaultOpen | boolean | 侧边栏的默认打开状态。 |
open | boolean | 侧边栏的打开状态(受控)。 |
onOpenChange | (open: boolean) => void | 设置侧边栏的打开状态(受控)。 |
宽度
如果您的应用程序中只有一个侧边栏,您可以使用 @/components/ui/sidebar/utils.ts 中的 SIDEBAR_WIDTH 和 SIDEBAR_WIDTH_MOBILE 常量来设置侧边栏的宽度。
export const SIDEBAR_WIDTH = "16rem";
export const SIDEBAR_WIDTH_MOBILE = "18rem";对于应用程序中的多个侧边栏,您可以使用 style prop 来设置侧边栏的宽度。
要设置侧边栏的宽度,您可以在 style prop 中使用 --sidebar-width 和 --sidebar-width-mobile CSS 变量。
<template>
<SidebarProvider
style="--sidebar-width: 20rem; --sidebar-width-mobile: 20rem;"
>
<Sidebar />
</SidebarProvider>
</template>这不仅会处理侧边栏的宽度,还会处理布局间距。
键盘快捷键
@/components/ui/sidebar/utils.ts 中的 SIDEBAR_KEYBOARD_SHORTCUT 变量用于设置打开和关闭侧边栏的键盘快捷键。
要触发侧边栏,您在 Mac 上使用 cmd+b 键盘快捷键,在 Windows 上使用 ctrl+b。
您可以通过更改 SIDEBAR_KEYBOARD_SHORTCUT 变量的值来更改键盘快捷键。
export const SIDEBAR_KEYBOARD_SHORTCUT = "b";持久化状态
SidebarProvider 支持在页面重新加载和服务器端渲染之间持久化侧边栏状态。它使用 cookie 来存储侧边栏的当前状态。当侧边栏状态更改时,会设置一个名为 sidebar_state 的默认 cookie,其中包含当前的打开/关闭状态。然后在后续页面加载时读取此 cookie 以恢复侧边栏状态。
要在 SSR 中持久化侧边栏状态,请在 App.vue 中像这样设置您的 SidebarProvider:
<!-- 使用 Nuxt -->
<script setup lang="ts">
import { SidebarProvider, SidebarTrigger } from "@/components/ui/sidebar"
import AppSidebar from "@/components/AppSidebar.vue"
const defaultOpen = useCookie<boolean>("sidebar_state");
</script>
<template>
<SidebarProvider :defaultOpen="defaultOpen">
<AppSidebar />
<main>
<SidebarTrigger />
<RouterView /> <!-- 或 <slot /> -->
</main>
</SidebarProvider>
</template>您可以通过更新 sidebar/utils.ts 中的 SIDEBAR_COOKIE_NAME 变量来更改 cookie 的名称。
export const SIDEBAR_COOKIE_NAME = "sidebar_state"Sidebar
主要的 Sidebar 组件,用于渲染可折叠侧边栏。
<script setup lang="ts">
import { Sidebar } from "@/components/ui/sidebar";
</script>
<template>
<Sidebar />
</template>Props
| 属性 | 类型 | 描述 |
|---|---|---|
side | left 或 right | 侧边栏的位置 |
variant | sidebar, floating, 或 inset | 侧边栏的变体 |
collapsible | offcanvas, icon, 或 none | 侧边栏的可折叠状态 |
side
使用 side prop 更改侧边栏的位置。
可用选项为 left 和 right。
<Sidebar side="left | right" />variant
使用 variant prop 更改侧边栏的变体。
可用选项为 sidebar、floating 和 inset。
<Sidebar variant="sidebar | floating | inset" />注意: 如果您使用 inset 变体,请记住将您的主要内容包装在 SidebarInset 组件中。
<template>
<SidebarProvider>
<Sidebar variant="inset">
<SidebarInset>
<main>
<slot />
</main>
</SidebarInset>
</Sidebar>
</SidebarProvider>
</template>collapsible
使用 collapsible prop 使侧边栏可折叠。
可用选项为 offcanvas、icon 和 none。
<Sidebar collapsible="offcanvas | icon | none" />| Prop | 描述 |
|---|---|
offcanvas | 一个可折叠的侧边栏,从左侧或右侧滑入。 |
icon | 一个可折叠为图标的侧边栏。 |
none | 一个不可折叠的侧边栏。 |
useSidebar
useSidebar 组合式函数用于控制侧边栏。
<script setup lang="ts">
import { useSidebar } from "@/components/ui/sidebar";
const {
state,
open,
setOpen,
openMobile,
setOpenMobile,
isMobile,
toggleSidebar,
} = useSidebar()
</script>| 属性 | 类型 | 描述 |
|---|---|---|
state | expanded 或 collapsed | 侧边栏的当前状态。 |
open | boolean | 侧边栏是否打开。 |
setOpen | (open: boolean) => void | 设置侧边栏的打开状态。 |
openMobile | boolean | 侧边栏在移动设备上是否打开。 |
setOpenMobile | (open: boolean) => void | 设置侧边栏在移动设备上的打开状态。 |
isMobile | boolean | 侧边栏是否在移动设备上。 |
toggleSidebar | () => void | 切换侧边栏。桌面和移动设备均适用。 |
SidebarHeader
使用 SidebarHeader 组件向侧边栏添加粘性标题。
以下示例向 SidebarHeader 添加了一个 <DropdownMenu>。
<template>
<Sidebar>
<SidebarHeader>
<SidebarMenu>
<SidebarMenuItem>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<SidebarMenuButton>
选择工作区
<ChevronDown class="ml-auto" />
</SidebarMenuButton>
</DropdownMenuTrigger>
<DropdownMenuContent class="w-[--bits-dropdown-menu-anchor-width]">
<DropdownMenuItem>
<span>Acme Inc</span>
</DropdownMenuItem>
<DropdownMenuItem>
<span>Acme Corp.</span>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</SidebarMenuItem>
</SidebarMenu>
</SidebarHeader>
</Sidebar>
</template>SidebarFooter
使用 SidebarFooter 组件向侧边栏添加粘性页脚。
以下示例向 SidebarFooter 添加了一个 <DropdownMenu>。
<template>
<SidebarProvider>
<Sidebar>
<SidebarHeader />
<SidebarContent />
<SidebarFooter>
<SidebarMenu>
<SidebarMenuItem>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<SidebarMenuButton>
<User2 /> 用户名
<ChevronUp class="ml-auto" />
</SidebarMenuButton>
</DropdownMenuTrigger>
<DropdownMenuContent
side="top"
class="w-[--reka-popper-anchor-width]"
>
<DropdownMenuItem>
<span>账户</span>
</DropdownMenuItem>
<DropdownMenuItem>
<span>账单</span>
</DropdownMenuItem>
<DropdownMenuItem>
<span>退出登录</span>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</SidebarMenuItem>
</SidebarMenu>
</SidebarFooter>
</Sidebar>
</SidebarProvider>
</template>SidebarContent
SidebarContent 组件用于包装侧边栏的内容。这是您添加 SidebarGroup 组件的地方。它是可滚动的。
<template>
<Sidebar>
<SidebarContent>
<SidebarGroup />
<SidebarGroup />
</SidebarContent>
</Sidebar>
</template>SidebarGroup
使用 SidebarGroup 组件在侧边栏内创建一个部分。
一个 SidebarGroup 有一个 SidebarGroupLabel、一个 SidebarGroupContent 和一个可选的 SidebarGroupAction。
<template>
<Sidebar>
<SidebarContent>
<SidebarGroup>
<SidebarGroupLabel>应用程序</SidebarGroupLabel>
<SidebarGroupAction>
<Plus /> <span class="sr-only">添加项目</span>
</SidebarGroupAction>
<SidebarGroupContent></SidebarGroupContent>
</SidebarGroup>
</SidebarContent>
</Sidebar>
</template>可折叠的 SidebarGroup
要使 SidebarGroup 可折叠,请将其包装在 Collapsible 中。
<template>
<Collapsible defaultOpen class="group/collapsible">
<SidebarGroup>
<SidebarGroupLabel asChild>
<CollapsibleTrigger>
帮助
<ChevronDown class="ml-auto transition-transform group-data-[state=open]/collapsible:rotate-180" />
</CollapsibleTrigger>
</SidebarGroupLabel>
<CollapsibleContent>
<SidebarGroupContent />
</CollapsibleContent>
</SidebarGroup>
</Collapsible>
</template>注意: 我们将 CollapsibleTrigger 包装在 SidebarGroupLabel 中以渲染一个按钮。
SidebarGroupAction
使用 SidebarGroupAction 组件向 SidebarGroup 添加操作。
<template>
<SidebarGroup>
<SidebarGroupLabel>项目</SidebarGroupLabel>
<SidebarGroupAction title="添加项目">
<Plus /> <span class="sr-only">添加项目</span>
</SidebarGroupAction>
<SidebarGroupContent />
</SidebarGroup>
</template>SidebarMenu
SidebarMenu 组件用于在 SidebarGroup 内构建菜单。
一个 SidebarMenu 由 SidebarMenuItem、SidebarMenuButton、SidebarMenuAction 和 SidebarMenuSub 组件组成。

以下是渲染项目列表的 SidebarMenu 组件示例。
<template>
<Sidebar>
<SidebarContent>
<SidebarGroup>
<SidebarGroupLabel>项目</SidebarGroupLabel>
<SidebarGroupContent>
<SidebarMenu>
<SidebarMenuItem v-for="project in projects" :key="project.name">
<SidebarMenuButton asChild>
<a :href="project.url">
<component :is="project.icon" />
<span>{{project.name}}</span>
</a>
</SidebarMenuButton>
</SidebarMenuItem>
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
</SidebarContent>
</Sidebar>
</template>SidebarMenuButton
SidebarMenuButton 组件用于在 SidebarMenuItem 内渲染菜单按钮。
链接或锚点
默认情况下,SidebarMenuButton 渲染一个按钮,但您可以使用 asChild prop 来渲染不同的组件,例如 <a> 标签。
<template>
<SidebarMenuButton asChild>
<a href="#">首页</a>
</SidebarMenuButton>
</template>图标和标签
您可以在按钮内渲染一个图标和一个被截断的标签。记得将标签包装在 <span> 标签中。
<template>
<SidebarMenuButton asChild>
<a href="#">
<Home />
<span>首页</span>
</a>
</SidebarMenuButton>
</template>isActive
使用 isActive prop 将菜单项标记为活动状态。
<template>
<SidebarMenuButton asChild isActive>
<a href="#">首页</a>
</SidebarMenuButton>
</template>SidebarMenuAction
SidebarMenuAction 组件用于在 SidebarMenuItem 内渲染菜单操作。
此按钮独立于 SidebarMenuButton 工作,即您可以将 SidebarMenuButton 作为可点击链接,而将 SidebarMenuAction 作为按钮。
<template>
<SidebarMenuItem>
<SidebarMenuButton asChild>
<a href="#">
<Home />
<span>首页</span>
</a>
</SidebarMenuButton>
<SidebarMenuAction>
<Plus /> <span class="sr-only">添加项目</span>
</SidebarMenuAction>
</SidebarMenuItem>
</template>DropdownMenu
以下是渲染 DropdownMenu 的 SidebarMenuAction 组件示例。
<template>
<SidebarMenuItem>
<SidebarMenuButton asChild>
<a href="#">
<Home />
<span>首页</span>
</a>
</SidebarMenuButton>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<SidebarMenuAction>
<MoreHorizontal />
</SidebarMenuAction>
</DropdownMenuTrigger>
<DropdownMenuContent side="right" align="start">
<DropdownMenuItem>
<span>编辑项目</span>
</DropdownMenuItem>
<DropdownMenuItem>
<span>删除项目</span>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</SidebarMenuItem>
</template>SidebarMenuSub
SidebarMenuSub 组件用于在 SidebarMenu 内渲染子菜单。
使用 SidebarMenuSubItem 和 SidebarMenuSubButton 来渲染子菜单项。
<template>
<SidebarMenuItem>
<SidebarMenuButton />
<SidebarMenuSub>
<SidebarMenuSubItem>
<SidebarMenuSubButton />
</SidebarMenuSubItem>
<SidebarMenuSubItem>
<SidebarMenuSubButton />
</SidebarMenuSubItem>
</SidebarMenuSub>
</SidebarMenuItem>
</template>可折叠的 SidebarMenu
要使 SidebarMenu 组件可折叠,请将其和 SidebarMenuSub 组件包装在 Collapsible 中。
<template>
<SidebarMenu>
<Collapsible defaultOpen class="group/collapsible">
<SidebarMenuItem>
<CollapsibleTrigger asChild>
<SidebarMenuButton />
</CollapsibleTrigger>
<CollapsibleContent>
<SidebarMenuSub>
<SidebarMenuSubItem />
</SidebarMenuSub>
</CollapsibleContent>
</SidebarMenuItem>
</Collapsible>
</SidebarMenu>
</template>SidebarMenuBadge
SidebarMenuBadge 组件用于在 SidebarMenuItem 内渲染徽章。
<template>
<SidebarMenuItem>
<SidebarMenuButton />
<SidebarMenuBadge>24</SidebarMenuBadge>
</SidebarMenuItem>
</template>SidebarMenuSkeleton
SidebarMenuSkeleton 组件用于在 SidebarMenu 内渲染骨架屏。您可以使用它来在等待数据加载时显示加载状态。
<template>
<SidebarMenu>
<SidebarMenuItem v-for="i in 5" :key="i">
<SidebarMenuSkeleton />
</SidebarMenuItem>
</SidebarMenu>
</template>SidebarSeparator
SidebarSeparator 组件用于在 Sidebar 内渲染分隔符。
<template>
<Sidebar>
<SidebarHeader />
<SidebarSeparator />
<SidebarContent>
<SidebarGroup />
<SidebarSeparator />
<SidebarGroup />
</SidebarContent>
</Sidebar>
</template>SidebarTrigger
使用 SidebarTrigger 组件渲染一个切换侧边栏的按钮。
SidebarTrigger 组件必须在 SidebarProvider 内使用。
<template>
<SidebarProvider>
<Sidebar />
<main>
<SidebarTrigger />
</main>
</SidebarProvider>
</template>自定义触发器
要创建自定义触发器,您可以使用 useSidebar 组合式函数。
<script setup lang="ts">
import { useSidebar } from "@/components/ui/sidebar";
const { toggleSidebar } = useSidebar();
</script>
<template>
<button @click="toggleSidebar">切换侧边栏</button>
</template>SidebarRail
SidebarRail 组件用于在 Sidebar 内渲染轨道。此轨道可用于切换侧边栏。
<template>
<Sidebar>
<SidebarHeader />
<SidebarContent>
<SidebarGroup />
</SidebarContent>
<SidebarFooter />
<SidebarRail />
</Sidebar>
</template>受控侧边栏
使用 open prop 和 @update:open 事件(或 v-model:open)来控制侧边栏状态。
<script setup lang="ts">
import { SidebarProvider, Sidebar } from "@/components/ui/sidebar";
import { ref } from "vue"
const open = ref(false)
</script>
<template>
<SidebarProvider v-model:open="open">
<Sidebar />
</SidebarProvider>
</template>主题定制
我们使用以下 CSS 变量来为主题化侧边栏。
@layer base {
:root {
--sidebar-background: 0 0% 98%;
--sidebar-foreground: 240 5.3% 26.1%;
--sidebar-primary: 240 5.9% 10%;
--sidebar-primary-foreground: 0 0% 98%;
--sidebar-accent: 240 4.8% 95.9%;
--sidebar-accent-foreground: 240 5.9% 10%;
--sidebar-border: 220 13% 91%;
--sidebar-ring: 217.2 91.2% 59.8%;
}
.dark {
--sidebar-background: 240 5.9% 10%;
--sidebar-foreground: 240 4.8% 95.9%;
--sidebar-primary: 0 0% 98%;
--sidebar-primary-foreground: 240 5.9% 10%;
--sidebar-accent: 240 3.7% 15.9%;
--sidebar-accent-foreground: 240 4.8% 95.9%;
--sidebar-border: 240 3.7% 15.9%;
--sidebar-ring: 217.2 91.2% 59.8%;
}
}我们特意为侧边栏和应用程序的其余部分使用不同的变量,以便轻松地使侧边栏的样式与应用程序的其余部分不同。想象一个侧边栏比主应用程序颜色更深的场景。
样式
以下是一些根据不同状态为侧边栏设置样式的技巧。
- 根据侧边栏可折叠状态设置元素样式。 以下将在侧边栏处于
icon模式时隐藏SidebarGroup。
<template>
<Sidebar collapsible="icon">
<SidebarContent>
<SidebarGroup class="group-data-[collapsible=icon]:hidden" />
</SidebarContent>
</Sidebar>
</template>- 根据菜单按钮活动状态设置菜单操作样式。 以下将在菜单按钮处于活动状态时强制显示菜单操作。
<template>
<SidebarMenuItem>
<SidebarMenuButton />
<SidebarMenuAction
class="peer-data-[active=true]/menu-button:opacity-100"
/>
</SidebarMenuItem>
</template>您可以在这篇 Twitter 帖子中找到更多关于使用状态进行样式设置的技巧。

