Docs
侧边栏

侧边栏

可组合、可主题化和可自定义的侧边栏组件。

sidebar-07

可折叠为图标的侧边栏。

¥A sidebar that collapses to icons.

侧边栏是最复杂的组件之一。它们是任何应用的核心,通常包含许多活动部件。

¥Sidebars are one of the most complex components to build. They are central to any application and often contain a lot of moving parts.

我不喜欢构建侧边栏。所以我构建了 30 多个。各种配置。然后我将核心组件提取到 sidebar.tsx 中。

¥I don't like building sidebars. So I built 30+ of them. All kinds of configurations. Then I extracted the core components into sidebar.tsx.

我们现在有一个坚实的基础可以在此基础上构建。可组合。可主题化。可定制。

¥We now have a solid foundation to build on top of. Composable. Themeable. Customizable.

浏览块库

¥Browse the Blocks Library.

安装

¥Installation

Run the following command to install sidebar.tsx

pnpm dlx shadcn@latest add sidebar

Add the following colors to your CSS file

上面的命令应该会为你安装颜色。如果没有,请将以下内容复制并粘贴到你的 CSS 文件中。

¥The command above should install the colors for you. If not, copy and paste the following in your CSS file.

我们将在 主题部分 中稍后介绍颜色。

¥We'll go over the colors later in the theming section.

app/globals.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%;
  }
}

结构

¥Structure

Sidebar 组件由以下部分组成:

¥A Sidebar component is composed of the following parts:

  • SidebarProvider - 处理可折叠状态。

    ¥SidebarProvider - Handles collapsible state.

  • Sidebar - 侧边栏容器。

    ¥Sidebar - The sidebar container.

  • SidebarHeaderSidebarFooter - 粘贴在侧边栏的顶部和底部。

    ¥SidebarHeader and SidebarFooter - Sticky at the top and bottom of the sidebar.

  • SidebarContent - 可滚动内容。

    ¥SidebarContent - Scrollable content.

  • SidebarGroup - SidebarContent 内的部分。

    ¥SidebarGroup - Section within the SidebarContent.

  • SidebarTrigger - Sidebar 的触发器。

    ¥SidebarTrigger - Trigger for the Sidebar.

Sidebar Structure

用法

¥Usage

app/layout.tsx
import { SidebarProvider, SidebarTrigger } from "@/components/ui/sidebar"
import { AppSidebar } from "@/components/app-sidebar"
 
export default function Layout({ children }: { children: React.ReactNode }) {
  return (
    <SidebarProvider>
      <AppSidebar />
      <main>
        <SidebarTrigger />
        {children}
      </main>
    </SidebarProvider>
  )
}
components/app-sidebar.tsx
import {
  Sidebar,
  SidebarContent,
  SidebarFooter,
  SidebarGroup,
  SidebarHeader,
} from "@/components/ui/sidebar"
 
export function AppSidebar() {
  return (
    <Sidebar>
      <SidebarHeader />
      <SidebarContent>
        <SidebarGroup />
        <SidebarGroup />
      </SidebarContent>
      <SidebarFooter />
    </Sidebar>
  )
}

你的第一个侧边栏

¥Your First Sidebar

让我们从最基本的侧边栏开始。带有菜单的可折叠侧边栏。

¥Let's start with the most basic sidebar. A collapsible sidebar with a menu.

在应用的根目录下添加 SidebarProviderSidebarTrigger

¥Add a SidebarProvider and SidebarTrigger at the root of your application.

app/layout.tsx
import { SidebarProvider, SidebarTrigger } from "@/components/ui/sidebar"
import { AppSidebar } from "@/components/app-sidebar"
 
export default function Layout({ children }: { children: React.ReactNode }) {
  return (
    <SidebarProvider>
      <AppSidebar />
      <main>
        <SidebarTrigger />
        {children}
      </main>
    </SidebarProvider>
  )
}

Create a new sidebar component at components/app-sidebar.tsx.

components/app-sidebar.tsx
import { Sidebar, SidebarContent } from "@/components/ui/sidebar"
 
export function AppSidebar() {
  return (
    <Sidebar>
      <SidebarContent />
    </Sidebar>
  )
}

Now, let's add a SidebarMenu to the sidebar.

我们将在 SidebarGroup 中使用 SidebarMenu 组件。

¥We'll use the SidebarMenu component in a SidebarGroup.

components/app-sidebar.tsx
import { Calendar, Home, Inbox, Search, Settings } from "lucide-react"
 
import {
  Sidebar,
  SidebarContent,
  SidebarGroup,
  SidebarGroupContent,
  SidebarGroupLabel,
  SidebarMenu,
  SidebarMenuButton,
  SidebarMenuItem,
} from "@/components/ui/sidebar"
 
// Menu items.
const items = [
  {
    title: "Home",
    url: "#",
    icon: Home,
  },
  {
    title: "Inbox",
    url: "#",
    icon: Inbox,
  },
  {
    title: "Calendar",
    url: "#",
    icon: Calendar,
  },
  {
    title: "Search",
    url: "#",
    icon: Search,
  },
  {
    title: "Settings",
    url: "#",
    icon: Settings,
  },
]
 
export function AppSidebar() {
  return (
    <Sidebar>
      <SidebarContent>
        <SidebarGroup>
          <SidebarGroupLabel>Application</SidebarGroupLabel>
          <SidebarGroupContent>
            <SidebarMenu>
              {items.map((item) => (
                <SidebarMenuItem key={item.title}>
                  <SidebarMenuButton asChild>
                    <a href={item.url}>
                      <item.icon />
                      <span>{item.title}</span>
                    </a>
                  </SidebarMenuButton>
                </SidebarMenuItem>
              ))}
            </SidebarMenu>
          </SidebarGroupContent>
        </SidebarGroup>
      </SidebarContent>
    </Sidebar>
  )
}

You've created your first sidebar.

sidebar-demo

你的第一个侧边栏。

¥Your first sidebar.

组件

¥Components

sidebar.tsx 中的组件是可组合的,即你可以通过将提供的组件放在一起来构建侧边栏。它们还可以与其他 shadcn/ui 组件(如 DropdownMenuCollapsibleDialog 等)很好地组合。

¥The components in sidebar.tsx are built to be composable i.e you build your sidebar by putting the provided components together. They also compose well with other shadcn/ui components such as DropdownMenu, Collapsible or Dialog etc.

如果你需要更改 sidebar.tsx 中的代码,我们鼓励你这样做。代码是你的。使用 sidebar.tsx 作为起点并构建你自己的。

¥If you need to change the code in sidebar.tsx, you are encouraged to do so. The code is yours. Use sidebar.tsx as a starting point and build your own.

在接下来的部分中,我们将介绍每个组件及其使用方法。

¥In the next sections, we'll go over each component and how to use them.

SidebarProvider

SidebarProvider 组件用于为 Sidebar 组件提供侧边栏上下文。你应该始终将你的应用封装在 SidebarProvider 组件中。

¥The SidebarProvider component is used to provide the sidebar context to the Sidebar component. You should always wrap your application in a SidebarProvider component.

属性

¥Props

名称类型描述
defaultOpenboolean侧边栏的默认打开状态。
openboolean侧边栏的打开状态(受控)。
onOpenChange(open: boolean) => void设置侧边栏的打开状态(受控)。

宽度

¥Width

如果你的应用中只有一个侧边栏,则可以使用 sidebar.tsx 中的 SIDEBAR_WIDTHSIDEBAR_WIDTH_MOBILE 变量来设置侧边栏的宽度。

¥If you have a single sidebar in your application, you can use the SIDEBAR_WIDTH and SIDEBAR_WIDTH_MOBILE variables in sidebar.tsx to set the width of the sidebar.

components/ui/sidebar.tsx
const SIDEBAR_WIDTH = "16rem"
const SIDEBAR_WIDTH_MOBILE = "18rem"

对于应用中的多个侧边栏,你可以使用 style prop 来设置侧边栏的宽度。

¥For multiple sidebars in your application, you can use the style prop to set the width of the sidebar.

要设置侧边栏的宽度,你可以在 style 属性中使用 --sidebar-width--sidebar-width-mobile CSS 变量。

¥To set the width of the sidebar, you can use the --sidebar-width and --sidebar-width-mobile CSS variables in the style prop.

components/ui/sidebar.tsx
<SidebarProvider
  style={{
    "--sidebar-width": "20rem",
    "--sidebar-width-mobile": "20rem",
  }}
>
  <Sidebar />
</SidebarProvider>

这将处理侧边栏的宽度以及布局间距。

¥This will handle the width of the sidebar but also the layout spacing.

键盘快捷方式

¥Keyboard Shortcut

SIDEBAR_KEYBOARD_SHORTCUT 变量用于设置用于打开和关闭侧边栏的键盘快捷键。

¥The SIDEBAR_KEYBOARD_SHORTCUT variable is used to set the keyboard shortcut used to open and close the sidebar.

要触发侧边栏,请在 Mac 上使用 cmd+b 键盘快捷键,在 Windows 上使用 ctrl+b

¥To trigger the sidebar, you use the cmd+b keyboard shortcut on Mac and ctrl+b on Windows.

你可以通过更新 SIDEBAR_KEYBOARD_SHORTCUT 变量来更改键盘快捷键。

¥You can change the keyboard shortcut by updating the SIDEBAR_KEYBOARD_SHORTCUT variable.

components/ui/sidebar.tsx
const SIDEBAR_KEYBOARD_SHORTCUT = "b"

持久状态

¥Persisted State

SidebarProvider 支持在页面重新加载和服务器端渲染时保持侧边栏状态。它使用 cookie 来存储侧边栏的当前状态。当侧边栏状态发生变化时,将使用当前打开/关闭状态设置一个名为 sidebar:state 的默认 cookie。然后在后续页面加载时读取此 cookie 以恢复侧边栏状态。

¥The SidebarProvider supports persisting the sidebar state across page reloads and server-side rendering. It uses cookies to store the current state of the sidebar. When the sidebar state changes, a default cookie named sidebar:state is set with the current open/closed state. This cookie is then read on subsequent page loads to restore the sidebar state.

要在 Next.js 中保留侧边栏状态,请在 app/layout.tsx 中像这样设置你的 SidebarProvider

¥To persist sidebar state in Next.js, set up your SidebarProvider in app/layout.tsx like this:

app/layout.tsx
import { cookies } from "next/headers"
 
import { SidebarProvider, SidebarTrigger } from "@/components/ui/sidebar"
import { AppSidebar } from "@/components/app-sidebar"
 
export async function Layout({ children }: { children: React.ReactNode }) {
  const cookieStore = await cookies()
  const defaultOpen = cookieStore.get("sidebar:state")?.value === "true"
 
  return (
    <SidebarProvider defaultOpen={defaultOpen}>
      <AppSidebar />
      <main>
        <SidebarTrigger />
        {children}
      </main>
    </SidebarProvider>
  )
}

你可以通过更新 sidebar.tsx 中的 SIDEBAR_COOKIE_NAME 变量来更改 cookie 的名称。

¥You can change the name of the cookie by updating the SIDEBAR_COOKIE_NAME variable in sidebar.tsx.

components/ui/sidebar.tsx
const SIDEBAR_COOKIE_NAME = "sidebar:state"

侧边栏

¥Sidebar

用于渲染可折叠侧边栏的主要 Sidebar 组件。

¥The main Sidebar component used to render a collapsible sidebar.

import { Sidebar } from "@/components/ui/sidebar"
 
export function AppSidebar() {
  return <Sidebar />
}

属性

¥Props

属性类型描述
sideleftright侧边栏的侧面。
variantsidebarfloatinginset侧边栏的变体。
collapsibleoffcanvasiconnone侧边栏的可折叠状态。

side

使用 side 属性更改侧边栏的侧面。

¥Use the side prop to change the side of the sidebar.

可用选项为 leftright

¥Available options are left and right.

import { Sidebar } from "@/components/ui/sidebar"
 
export function AppSidebar() {
  return <Sidebar side="left | right" />
}

variant

使用 variant 属性更改侧边栏的变体。

¥Use the variant prop to change the variant of the sidebar.

可用选项为 sidebarfloatinginset

¥Available options are sidebar, floating and inset.

import { Sidebar } from "@/components/ui/sidebar"
 
export function AppSidebar() {
  return <Sidebar variant="sidebar | floating | inset" />
}
<SidebarProvider>
  <Sidebar variant="inset" />
  <SidebarInset>
    <main>{children}</main>
  </SidebarInset>
</SidebarProvider>

collapsible

使用 collapsible 属性使侧边栏可折叠。

¥Use the collapsible prop to make the sidebar collapsible.

可用选项为 offcanvasiconnone

¥Available options are offcanvas, icon and none.

import { Sidebar } from "@/components/ui/sidebar"
 
export function AppSidebar() {
  return <Sidebar collapsible="offcanvas | icon | none" />
}
Prop描述
offcanvas可从左侧或右侧滑入的可折叠侧边栏。
icon可折叠为图标的侧边栏。
none不可折叠侧边栏。

useSidebar

useSidebar 钩子用于控制侧边栏。

¥The useSidebar hook is used to control the sidebar.

import { useSidebar } from "@/components/ui/sidebar"
 
export function AppSidebar() {
  const {
    state,
    open,
    setOpen,
    openMobile,
    setOpenMobile,
    isMobile,
    toggleSidebar,
  } = useSidebar()
}
属性类型描述
stateexpandedcollapsed侧边栏的当前状态。
openboolean侧边栏是否打开。
setOpen(open: boolean) => void设置侧边栏的打开状态。
openMobileboolean侧边栏是否在移动设备上打开。
setOpenMobile(open: boolean) => void设置移动设备上侧边栏的打开状态。
isMobileboolean侧边栏是否在移动设备上。
toggleSidebar() => void切换侧边栏。桌面和移动设备。

SidebarHeader

使用 SidebarHeader 组件向侧边栏添加粘性标题。

¥Use the SidebarHeader component to add a sticky header to the sidebar.

以下示例将 <DropdownMenu> 添加到 SidebarHeader

¥The following example adds a <DropdownMenu> to the SidebarHeader.

sidebar-header

带有下拉菜单的侧边栏标题。

¥A sidebar header with a dropdown menu.

components/app-sidebar.tsx
<Sidebar>
  <SidebarHeader>
    <SidebarMenu>
      <SidebarMenuItem>
        <DropdownMenu>
          <DropdownMenuTrigger asChild>
            <SidebarMenuButton>
              Select Workspace
              <ChevronDown className="ml-auto" />
            </SidebarMenuButton>
          </DropdownMenuTrigger>
          <DropdownMenuContent className="w-[--radix-popper-anchor-width]">
            <DropdownMenuItem>
              <span>Acme Inc</span>
            </DropdownMenuItem>
            <DropdownMenuItem>
              <span>Acme Corp.</span>
            </DropdownMenuItem>
          </DropdownMenuContent>
        </DropdownMenu>
      </SidebarMenuItem>
    </SidebarMenu>
  </SidebarHeader>
</Sidebar>

SidebarFooter

使用 SidebarFooter 组件向侧边栏添加粘性页脚。

¥Use the SidebarFooter component to add a sticky footer to the sidebar.

以下示例将 <DropdownMenu> 添加到 SidebarFooter

¥The following example adds a <DropdownMenu> to the SidebarFooter.

sidebar-footer

带有下拉菜单的侧边栏页脚。

¥A sidebar footer with a dropdown menu.

components/app-sidebar.tsx
export function AppSidebar() {
  return (
    <SidebarProvider>
      <Sidebar>
        <SidebarHeader />
        <SidebarContent />
        <SidebarFooter>
          <SidebarMenu>
            <SidebarMenuItem>
              <DropdownMenu>
                <DropdownMenuTrigger asChild>
                  <SidebarMenuButton>
                    <User2 /> Username
                    <ChevronUp className="ml-auto" />
                  </SidebarMenuButton>
                </DropdownMenuTrigger>
                <DropdownMenuContent
                  side="top"
                  className="w-[--radix-popper-anchor-width]"
                >
                  <DropdownMenuItem>
                    <span>Account</span>
                  </DropdownMenuItem>
                  <DropdownMenuItem>
                    <span>Billing</span>
                  </DropdownMenuItem>
                  <DropdownMenuItem>
                    <span>Sign out</span>
                  </DropdownMenuItem>
                </DropdownMenuContent>
              </DropdownMenu>
            </SidebarMenuItem>
          </SidebarMenu>
        </SidebarFooter>
      </Sidebar>
    </SidebarProvider>
  )
}

SidebarContent

SidebarContent 组件用于封装侧边栏的内容。这是你添加 SidebarGroup 组件的地方。它是可滚动的。

¥The SidebarContent component is used to wrap the content of the sidebar. This is where you add your SidebarGroup components. It is scrollable.

import { Sidebar, SidebarContent } from "@/components/ui/sidebar"
 
export function AppSidebar() {
  return (
    <Sidebar>
      <SidebarContent>
        <SidebarGroup />
        <SidebarGroup />
      </SidebarContent>
    </Sidebar>
  )
}

SidebarGroup

使用 SidebarGroup 组件在侧边栏内创建一个部分。

¥Use the SidebarGroup component to create a section within the sidebar.

SidebarGroupSidebarGroupLabelSidebarGroupContent 和可选的 SidebarGroupAction

¥A SidebarGroup has a SidebarGroupLabel, a SidebarGroupContent and an optional SidebarGroupAction.

sidebar-group

侧边栏组。

¥A sidebar group.

import { Sidebar, SidebarContent, SidebarGroup } from "@/components/ui/sidebar"
 
export function AppSidebar() {
  return (
    <Sidebar>
      <SidebarContent>
        <SidebarGroup>
          <SidebarGroupLabel>Application</SidebarGroupLabel>
          <SidebarGroupAction>
            <Plus /> <span className="sr-only">Add Project</span>
          </SidebarGroupAction>
          <SidebarGroupContent></SidebarGroupContent>
        </SidebarGroup>
      </SidebarContent>
    </Sidebar>
  )
}

可折叠侧边栏组

¥Collapsible SidebarGroup

要使 SidebarGroup 可折叠,请将其封装在 Collapsible 中。

¥To make a SidebarGroup collapsible, wrap it in a Collapsible.

sidebar-group-collapsible

可折叠侧边栏组。

¥A collapsible sidebar group.

export function AppSidebar() {
  return (
    <Collapsible defaultOpen className="group/collapsible">
      <SidebarGroup>
        <SidebarGroupLabel asChild>
          <CollapsibleTrigger>
            Help
            <ChevronDown className="ml-auto transition-transform group-data-[state=open]/collapsible:rotate-180" />
          </CollapsibleTrigger>
        </SidebarGroupLabel>
        <CollapsibleContent>
          <SidebarGroupContent />
        </CollapsibleContent>
      </SidebarGroup>
    </Collapsible>
  )
}

SidebarGroupAction

使用 SidebarGroupAction 组件向 SidebarGroup 添加操作按钮。

¥Use the SidebarGroupAction component to add an action button to the SidebarGroup.

export function AppSidebar() {
  return (
    <SidebarGroup>
      <SidebarGroupLabel asChild>Projects</SidebarGroupLabel>
      <SidebarGroupAction title="Add Project">
        <Plus /> <span className="sr-only">Add Project</span>
      </SidebarGroupAction>
      <SidebarGroupContent />
    </SidebarGroup>
  )
}
sidebar-group-action

带有操作按钮的侧边栏组。

¥A sidebar group with an action button.

SidebarMenu

SidebarMenu 组件用于在 SidebarGroup 中构建菜单。

¥The SidebarMenu component is used for building a menu within a SidebarGroup.

SidebarMenu 组件由 SidebarMenuItemSidebarMenuButton<SidebarMenuAction /><SidebarMenuSub /> 组件组成。

¥A SidebarMenu component is composed of SidebarMenuItem, SidebarMenuButton, <SidebarMenuAction /> and <SidebarMenuSub /> components.

Sidebar Menu

以下是 SidebarMenu 组件渲染项目列表的示例。

¥Here's an example of a SidebarMenu component rendering a list of projects.

sidebar-menu

带有项目列表的侧边栏菜单。

¥A sidebar menu with a list of projects.

<Sidebar>
  <SidebarContent>
    <SidebarGroup>
      <SidebarGroupLabel>Projects</SidebarGroupLabel>
      <SidebarGroupContent>
        <SidebarMenu>
          {projects.map((project) => (
            <SidebarMenuItem key={project.name}>
              <SidebarMenuButton asChild>
                <a href={project.url}>
                  <project.icon />
                  <span>{project.name}</span>
                </a>
              </SidebarMenuButton>
            </SidebarMenuItem>
          ))}
        </SidebarMenu>
      </SidebarGroupContent>
    </SidebarGroup>
  </SidebarContent>
</Sidebar>

SidebarMenuButton

SidebarMenuButton 组件用于在 SidebarMenuItem 中渲染菜单按钮。

¥The SidebarMenuButton component is used to render a menu button within a SidebarMenuItem.

链接或锚点

¥Link or Anchor

默认情况下,SidebarMenuButton 渲染一个按钮,但你可以使用 asChild prop 来渲染不同的组件,例如 Linka 标签。

¥By default, the SidebarMenuButton renders a button but you can use the asChild prop to render a different component such as a Link or an a tag.

<SidebarMenuButton asChild>
  <a href="#">Home</a>
</SidebarMenuButton>

图标和标签

¥Icon and Label

你可以在按钮内渲染图标和截断标签。请记住将标签封装在 <span> 中。

¥You can render an icon and a truncated label inside the button. Remember to wrap the label in a <span>.

<SidebarMenuButton asChild>
  <a href="#">
    <Home />
    <span>Home</span>
  </a>
</SidebarMenuButton>

isActive

使用 isActive 属性将菜单项标记为活动。

¥Use the isActive prop to mark a menu item as active.

<SidebarMenuButton asChild isActive>
  <a href="#">Home</a>
</SidebarMenuButton>

SidebarMenuAction

SidebarMenuAction 组件用于在 SidebarMenuItem 中渲染菜单操作。

¥The SidebarMenuAction component is used to render a menu action within a SidebarMenuItem.

此按钮独立于 SidebarMenuButton 工作,即你可以将 <SidebarMenuButton /> 作为可点击链接,将 <SidebarMenuAction /> 作为按钮。

¥This button works independently of the SidebarMenuButton i.e you can have the <SidebarMenuButton /> as a clickable link and the <SidebarMenuAction /> as a button.

<SidebarMenuItem>
  <SidebarMenuButton asChild>
    <a href="#">
      <Home />
      <span>Home</span>
    </a>
  </SidebarMenuButton>
  <SidebarMenuAction>
    <Plus /> <span className="sr-only">Add Project</span>
  </SidebarMenuAction>
</SidebarMenuItem>

以下是 SidebarMenuAction 组件渲染 DropdownMenu 的示例。

¥Here's an example of a SidebarMenuAction component rendering a DropdownMenu.

sidebar-menu-action

带有下拉菜单的侧边栏菜单操作。

¥A sidebar menu action with a dropdown menu.

<SidebarMenuItem>
  <SidebarMenuButton asChild>
    <a href="#">
      <Home />
      <span>Home</span>
    </a>
  </SidebarMenuButton>
  <DropdownMenu>
    <DropdownMenuTrigger asChild>
      <SidebarMenuAction>
        <MoreHorizontal />
      </SidebarMenuAction>
    </DropdownMenuTrigger>
    <DropdownMenuContent side="right" align="start">
      <DropdownMenuItem>
        <span>Edit Project</span>
      </DropdownMenuItem>
      <DropdownMenuItem>
        <span>Delete Project</span>
      </DropdownMenuItem>
    </DropdownMenuContent>
  </DropdownMenu>
</SidebarMenuItem>

SidebarMenuSub

SidebarMenuSub 组件用于在 SidebarMenu 中渲染子菜单。

¥The SidebarMenuSub component is used to render a submenu within a SidebarMenu.

使用 <SidebarMenuSubItem /><SidebarMenuSubButton /> 渲染子菜单项。

¥Use <SidebarMenuSubItem /> and <SidebarMenuSubButton /> to render a submenu item.

sidebar-menu-sub

带有子菜单的侧边栏菜单。

¥A sidebar menu with a submenu.

<SidebarMenuItem>
  <SidebarMenuButton />
  <SidebarMenuSub>
    <SidebarMenuSubItem>
      <SidebarMenuSubButton />
    </SidebarMenuSubItem>
    <SidebarMenuSubItem>
      <SidebarMenuSubButton />
    </SidebarMenuSubItem>
  </SidebarMenuSub>
</SidebarMenuItem>

可折叠侧边栏菜单

¥Collapsible SidebarMenu

要使 SidebarMenu 组件可折叠,请将其和 SidebarMenuSub 组件封装在 Collapsible 中。

¥To make a SidebarMenu component collapsible, wrap it and the SidebarMenuSub components in a Collapsible.

sidebar-menu-collapsible

可折叠侧边栏菜单。

¥A collapsible sidebar menu.

<SidebarMenu>
  <Collapsible defaultOpen className="group/collapsible">
    <SidebarMenuItem>
      <CollapsibleTrigger asChild>
        <SidebarMenuButton />
      </CollapsibleTrigger>
      <CollapsibleContent>
        <SidebarMenuSub>
          <SidebarMenuSubItem />
        </SidebarMenuSub>
      </CollapsibleContent>
    </SidebarMenuItem>
  </Collapsible>
</SidebarMenu>

SidebarMenuBadge

SidebarMenuBadge 组件用于在 SidebarMenuItem 中渲染徽章。

¥The SidebarMenuBadge component is used to render a badge within a SidebarMenuItem.

sidebar-menu-badge

带有徽章的侧边栏菜单。

¥A sidebar menu with a badge.

<SidebarMenuItem>
  <SidebarMenuButton />
  <SidebarMenuBadge>24</SidebarMenuBadge>
</SidebarMenuItem>

SidebarMenuSkeleton

SidebarMenuSkeleton 组件用于为 SidebarMenu 渲染骨架。你可以使用它来在使用 React Server Components、SWR 或 react-query 时显示加载状态。

¥The SidebarMenuSkeleton component is used to render a skeleton for a SidebarMenu. You can use this to show a loading state when using React Server Components, SWR or react-query.

function NavProjectsSkeleton() {
  return (
    <SidebarMenu>
      {Array.from({ length: 5 }).map((_, index) => (
        <SidebarMenuItem key={index}>
          <SidebarMenuSkeleton />
        </SidebarMenuItem>
      ))}
    </SidebarMenu>
  )
}

SidebarSeparator

SidebarSeparator 组件用于在 Sidebar 中渲染分隔符。

¥The SidebarSeparator component is used to render a separator within a Sidebar.

<Sidebar>
  <SidebarHeader />
  <SidebarSeparator />
  <SidebarContent>
    <SidebarGroup />
    <SidebarSeparator />
    <SidebarGroup />
  </SidebarContent>
</Sidebar>

SidebarTrigger

使用 SidebarTrigger 组件渲染切换侧边栏的按钮。

¥Use the SidebarTrigger component to render a button that toggles the sidebar.

SidebarTrigger 组件必须在 SidebarProvider 中使用。

¥The SidebarTrigger component must be used within a SidebarProvider.

<SidebarProvider>
  <Sidebar />
  <main>
    <SidebarTrigger />
  </main>
</SidebarProvider>

自定义触发器

¥Custom Trigger

要创建自定义触发器,你可以使用 useSidebar 钩子。

¥To create a custom trigger, you can use the useSidebar hook.

import { useSidebar } from "@/components/ui/sidebar"
 
export function CustomTrigger() {
  const { toggleSidebar } = useSidebar()
 
  return <button onClick={toggleSidebar}>Toggle Sidebar</button>
}

SidebarRail

SidebarRail 组件用于在 Sidebar 中渲染轨道。此轨道可用于切换侧边栏。

¥The SidebarRail component is used to render a rail within a Sidebar. This rail can be used to toggle the sidebar.

<Sidebar>
  <SidebarHeader />
  <SidebarContent>
    <SidebarGroup />
  </SidebarContent>
  <SidebarFooter />
  <SidebarRail />
</Sidebar>

数据获取

¥Data Fetching

React 服务器组件

¥React Server Components

以下是使用 React Server Components 渲染项目列表的 SidebarMenu 组件的示例。

¥Here's an example of a SidebarMenu component rendering a list of projects using React Server Components.

sidebar-rsc

使用 React Server Components 的侧边栏菜单。

¥A sidebar menu using React Server Components.

Skeleton to show loading state.
function NavProjectsSkeleton() {
  return (
    <SidebarMenu>
      {Array.from({ length: 5 }).map((_, index) => (
        <SidebarMenuItem key={index}>
          <SidebarMenuSkeleton showIcon />
        </SidebarMenuItem>
      ))}
    </SidebarMenu>
  )
}
Server component fetching data.
async function NavProjects() {
  const projects = await fetchProjects()
 
  return (
    <SidebarMenu>
      {projects.map((project) => (
        <SidebarMenuItem key={project.name}>
          <SidebarMenuButton asChild>
            <a href={project.url}>
              <project.icon />
              <span>{project.name}</span>
            </a>
          </SidebarMenuButton>
        </SidebarMenuItem>
      ))}
    </SidebarMenu>
  )
}
Usage with React Suspense.
function AppSidebar() {
  return (
    <Sidebar>
      <SidebarContent>
        <SidebarGroup>
          <SidebarGroupLabel>Projects</SidebarGroupLabel>
          <SidebarGroupContent>
            <React.Suspense fallback={<NavProjectsSkeleton />}>
              <NavProjects />
            </React.Suspense>
          </SidebarGroupContent>
        </SidebarGroup>
      </SidebarContent>
    </Sidebar>
  )
}

SWR 和 React 查询

¥SWR and React Query

你可以使用相同的方法对 SWRreact-query 进行操作。

¥You can use the same approach with SWR or react-query.

SWR
function NavProjects() {
  const { data, isLoading } = useSWR("/api/projects", fetcher)
 
  if (isLoading) {
    return (
      <SidebarMenu>
        {Array.from({ length: 5 }).map((_, index) => (
          <SidebarMenuItem key={index}>
            <SidebarMenuSkeleton showIcon />
          </SidebarMenuItem>
        ))}
      </SidebarMenu>
    )
  }
 
  if (!data) {
    return ...
  }
 
  return (
    <SidebarMenu>
      {data.map((project) => (
        <SidebarMenuItem key={project.name}>
          <SidebarMenuButton asChild>
            <a href={project.url}>
              <project.icon />
              <span>{project.name}</span>
            </a>
          </SidebarMenuButton>
        </SidebarMenuItem>
      ))}
    </SidebarMenu>
  )
}
React Query
function NavProjects() {
  const { data, isLoading } = useQuery()
 
  if (isLoading) {
    return (
      <SidebarMenu>
        {Array.from({ length: 5 }).map((_, index) => (
          <SidebarMenuItem key={index}>
            <SidebarMenuSkeleton showIcon />
          </SidebarMenuItem>
        ))}
      </SidebarMenu>
    )
  }
 
  if (!data) {
    return ...
  }
 
  return (
    <SidebarMenu>
      {data.map((project) => (
        <SidebarMenuItem key={project.name}>
          <SidebarMenuButton asChild>
            <a href={project.url}>
              <project.icon />
              <span>{project.name}</span>
            </a>
          </SidebarMenuButton>
        </SidebarMenuItem>
      ))}
    </SidebarMenu>
  )
}

受控侧边栏

¥Controlled Sidebar

使用 openonOpenChange 属性来控制侧边栏。

¥Use the open and onOpenChange props to control the sidebar.

sidebar-controlled

受控侧边栏。

¥A controlled sidebar.

export function AppSidebar() {
  const [open, setOpen] = React.useState(false)
 
  return (
    <SidebarProvider open={open} onOpenChange={setOpen}>
      <Sidebar />
    </SidebarProvider>
  )
}

主题

¥Theming

我们使用以下 CSS 变量来设置侧边栏的主题。

¥We use the following CSS variables to theme the sidebar.

@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%;
  }
}

我们有意为侧边栏和应用的其余部分使用不同的变量,以便轻松拥有与应用其余部分不同样式的侧边栏。想象一下主应用中带有深色阴影的侧边栏。

¥We intentionally use different variables for the sidebar and the rest of the application to make it easy to have a sidebar that is styled differently from the rest of the application. Think a sidebar with a darker shade from the main application.

样式

¥Styling

以下是根据不同状态设置侧边栏样式的一些技巧。

¥Here are some tips for styling the sidebar based on different states.

  • 根据侧边栏可折叠状态设置元素样式。当侧边栏处于 icon 模式时,以下内容将隐藏 SidebarGroup

    ¥Styling an element based on the sidebar collapsible state. The following will hide the SidebarGroup when the sidebar is in icon mode.

<Sidebar collapsible="icon">
  <SidebarContent>
    <SidebarGroup className="group-data-[collapsible=icon]:hidden" />
  </SidebarContent>
</Sidebar>
  • 根据菜单按钮活动状态设置菜单操作的样式。以下内容将强制菜单操作在菜单按钮处于活动状态时可见。

    ¥Styling a menu action based on the menu button active state. The following will force the menu action to be visible when the menu button is active.

<SidebarMenuItem>
  <SidebarMenuButton />
  <SidebarMenuAction className="peer-data-[active=true]/menu-button:opacity-100" />
</SidebarMenuItem>

你可以在此 Twitter 线程 中找到有关使用状态进行样式设置的更多提示。

¥You can find more tips on using states for styling in this Twitter thread.

更新日志

¥Changelog

¥2024-10-30 Cookie handling in setOpen

  • #5593 - 改进了 <SidebarProvider> 中的 setOpen 回调逻辑。

    ¥#5593 - Improved setOpen callback logic in <SidebarProvider>.

更新 <SidebarProvider> 中的 setOpen 回调如下:

¥Update the setOpen callback in <SidebarProvider> as follows:

const setOpen = React.useCallback(
  (value: boolean | ((value: boolean) => boolean)) => {
    const openState = typeof value === "function" ? value(open) : value
    if (setOpenProp) {
      setOpenProp(openState)
    } else {
      _setOpen(openState)
    }
 
    // This sets the cookie to keep the sidebar state.
    document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`
  },
  [setOpenProp, open]
)

2024-10-21 修复 text-sidebar-foreground

¥2024-10-21 Fixed text-sidebar-foreground

  • #5491 - 将 text-sidebar-foreground<SidebarProvider> 移动到 <Sidebar> 组件。

    ¥#5491 - Moved text-sidebar-foreground from <SidebarProvider> to <Sidebar> component.

2024-10-20 useSidebar 钩子中的拼写错误。

¥2024-10-20 Typo in useSidebar hook.

修复了 useSidebar 钩子中的拼写错误。

¥Fixed typo in useSidebar hook.

sidebar.tsx
-  throw new Error("useSidebar must be used within a Sidebar.")
+  throw new Error("useSidebar must be used within a SidebarProvider.")