文档
侧边栏

侧边栏

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

sidebar-07

一个可以折叠成图标的侧边栏。

侧边栏是最难构建的组件之一。它们是任何应用程序的核心,并且通常包含许多移动部件。

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

我们现在有了一个坚实的基础可以构建。可组合。可主题化。可自定义。

浏览区块库.

安装

运行以下命令来安装 sidebar.tsx

pnpm dlx shadcn@latest add sidebar

将以下颜色添加到您的 CSS 文件中

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

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

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

结构

Sidebar 组件由以下部分组成

  • SidebarProvider - 处理可折叠状态。
  • Sidebar - 侧边栏容器。
  • SidebarHeaderSidebarFooter - 粘性定位在侧边栏的顶部和底部。
  • SidebarContent - 可滚动内容。
  • SidebarGroup - SidebarContent 中的部分。
  • SidebarTrigger - Sidebar 的触发器。
Sidebar Structure

用法

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>
  )
}

您的第一个侧边栏

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

在应用程序的根目录添加 SidebarProviderSidebarTrigger

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 创建一个新的侧边栏组件。

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

现在,让我们向侧边栏添加一个 SidebarMenu

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

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>
  )
}

您已经创建了您的第一个侧边栏。

sidebar-demo

您的第一个侧边栏。

组件

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

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

在接下来的章节中,我们将介绍每个组件以及如何使用它们。

SidebarProvider

SidebarProvider 组件用于向 Sidebar 组件提供侧边栏上下文。您应该始终将您的应用程序包裹在 SidebarProvider 组件中。

属性

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

宽度

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

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

对于您的应用程序中的多个侧边栏,您可以使用 style 属性来设置侧边栏的宽度。

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

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

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

键盘快捷键

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

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

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

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

持久化状态

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

要在 Next.js 中持久化侧边栏状态,请在 app/layout.tsx 中像这样设置您的 SidebarProvider

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 的名称。

components/ui/sidebar.tsx
const SIDEBAR_COOKIE_NAME = "sidebar_state"

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

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

属性

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

side

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

可用选项为 leftright

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

variant

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

可用选项为 sidebarfloatinginset

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 属性使侧边栏可折叠。

可用选项为 offcanvasiconnone

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

useSidebar

useSidebar Hook 用于控制侧边栏。

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

SidebarHeader

使用 SidebarHeader 组件向侧边栏添加粘性头部。

以下示例向 SidebarHeader 添加了一个 <DropdownMenu>

sidebar-header

带有下拉菜单的侧边栏头部。

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 组件向侧边栏添加粘性页脚。

以下示例向 SidebarFooter 添加了一个 <DropdownMenu>

sidebar-footer

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

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 组件。它是可滚动的。

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

SidebarGroup

使用 SidebarGroup 组件在侧边栏中创建一个 section。

一个 SidebarGroup 包含一个 SidebarGroupLabel、一个 SidebarGroupContent 和一个可选的 SidebarGroupAction

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 中。

sidebar-group-collapsible

一个可折叠的侧边栏组。

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 添加一个操作按钮。

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

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

SidebarMenu

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

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

Sidebar Menu

这是一个 SidebarMenu 组件渲染项目列表的示例。

sidebar-menu

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

<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 中渲染菜单按钮。

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

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

图标和标签

您可以在按钮内渲染图标和截断的标签。请记住将标签包裹在 <span> 中。

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

isActive

使用 isActive prop 将菜单项标记为活动状态。

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

SidebarMenuAction

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

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

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

这是一个 SidebarMenuAction 组件渲染 DropdownMenu 的示例。

sidebar-menu-action

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

<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 中渲染子菜单。

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

sidebar-menu-sub

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

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

Collapsible SidebarMenu

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

sidebar-menu-collapsible

一个可折叠的侧边栏菜单。

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

SidebarMenuBadge

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

sidebar-menu-badge

一个带有徽章的侧边栏菜单。

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

SidebarMenuSkeleton

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

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

SidebarSeparator

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

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

SidebarTrigger

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

SidebarTrigger 组件必须在 SidebarProvider 中使用。

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

Custom Trigger

要创建自定义触发器,您可以使用 useSidebar hook。

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

SidebarRail

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

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

数据获取

React Server Components

这是一个 SidebarMenu 组件使用 React Server Components 渲染项目列表的示例。

sidebar-rsc

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

用于显示加载状态的骨架屏。
function NavProjectsSkeleton() {
  return (
    <SidebarMenu>
      {Array.from({ length: 5 }).map((_, index) => (
        <SidebarMenuItem key={index}>
          <SidebarMenuSkeleton showIcon />
        </SidebarMenuItem>
      ))}
    </SidebarMenu>
  )
}
服务器组件获取数据。
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>
  )
}
与 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 Query

您可以将相同的方法与 SWRreact-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>
  )
}

受控侧边栏

使用 openonOpenChange props 来控制侧边栏。

sidebar-controlled

一个受控侧边栏。

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

主题化

我们使用以下 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
<Sidebar collapsible="icon">
  <SidebarContent>
    <SidebarGroup className="group-data-[collapsible=icon]:hidden" />
  </SidebarContent>
</Sidebar>
  • 基于菜单按钮活动状态样式化菜单操作。 以下代码将强制菜单操作在菜单按钮处于活动状态时可见。
<SidebarMenuItem>
  <SidebarMenuButton />
  <SidebarMenuAction className="peer-data-[active=true]/menu-button:opacity-100" />
</SidebarMenuItem>

您可以在此 Twitter 帖子中找到更多关于使用状态进行样式化的技巧。

更新日志

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

按如下方式更新 <SidebarProvider> 中的 setOpen 回调

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

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

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

修复了 useSidebar hook 中的拼写错误。

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