侧边栏 Sidebar
一个可组合、可主题化且可自定义的侧边栏组件
侧边栏是最复杂的组件之一,它们是任何应用程序的核心部分,通常包含许多动态元素。
我并不喜欢构建侧边栏,所以我构建了 30 多个不同配置的侧边栏,然后,我将核心组件提取到了 sidebar.tsx 文件中。
现在,我们有了一个坚实的基础,可以在其上进行构建——可组合、可主题化、可自定义。
Installation
运行以下命令进行安装sidebar.tsx
pnpm dlx shadcn@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
- 固定(Sticky)在侧边栏的顶部和底部SidebarContent
- 可滚动内容SidebarGroup
-SidebarContent
中的一个部分SidebarTrigger
- 触发Sidebar
的按钮
使用示例
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>
)
}
import {
Sidebar,
SidebarContent,
SidebarFooter,
SidebarGroup,
SidebarHeader,
} from "@/components/ui/sidebar"
export function AppSidebar() {
return (
<Sidebar>
<SidebarHeader />
<SidebarContent>
<SidebarGroup />
<SidebarGroup />
</SidebarContent>
<SidebarFooter />
</Sidebar>
)
}
第一个 Sidebar
让我们从最基础的侧边栏开始,一个可折叠的侧边栏,里面有菜单。
在应用的根目录添加 SidebarProvider
和 SidebarTrigger
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 } from "@/components/ui/sidebar"
export function AppSidebar() {
return (
<Sidebar>
<SidebarContent />
</Sidebar>
)
}
现在,添加一个 SidebarMenu
到侧边栏
我们将在 SidebarGroup
中使用 SidebarMenu
组件
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.tsx
中的组件是可组合的,即你可以通过将提供的组件组合在一起构建侧边栏,它们还可以很好地与其他 shadcn/ui 组件(如 DropdownMenu
, Collapsible
或 Dialog
等)一起使用
如果你需要修改 sidebar.tsx
中的代码,可以随意更改。代码是你的,可以以 sidebar.tsx
作为起点并根据需求进行自定义。
在接下来的部分中,我们将详细介绍每个组件及其使用方法
SidebarProvider
SidebarProvider
组件用于提供侧边栏的上下文。你应该始终在你的应用程序中将其包裹在 SidebarProvider
组件中。
Props
Name | Type | Description |
---|---|---|
defaultOpen | boolean | 侧边栏的默认打开状态 |
open | boolean | 侧边栏的打开状态(受控) |
onOpenChange | (open: boolean) => void | 设置侧边栏的打开状态(受控) |
Width
如果你的应用中只有一个侧边栏,你可以在 sidebar.tsx
文件中使用 SIDEBAR_WIDTH
和 SIDEBAR_WIDTH_MOBILE
变量来设置侧边栏的宽度。
const SIDEBAR_WIDTH = "16rem"
const SIDEBAR_WIDTH_MOBILE = "18rem"
如果你的应用中有多个侧边栏,你可以使用 style
属性来设置侧边栏的宽度。
你可以在 style
属性中使用 --sidebar-width
和 --sidebar-width-mobile
CSS 变量来设置侧边栏的宽度。
<SidebarProvider
style={{
"--sidebar-width": "20rem",
"--sidebar-width-mobile": "20rem",
}}
>
<Sidebar />
</SidebarProvider>
这将同时处理侧边栏的宽度和布局的间距。
键盘快捷键
SIDEBAR_KEYBOARD_SHORTCUT
变量用于设置打开和关闭侧边栏的键盘快捷键。
在 Mac 上,使用 cmd+b
快捷键,Windows 上使用 ctrl+b
快捷键来触发侧边栏。
你可以通过更新 SIDEBAR_KEYBOARD_SHORTCUT
变量来修改快捷键
const SIDEBAR_KEYBOARD_SHORTCUT = "b"
持久化状态
SidebarProvider
支持跨页面重载和服务器端渲染时持久化侧边栏状态。它使用 cookies 来存储当前的侧边栏状态。当侧边栏状态发生变化时,会设置一个默认的 cookie,名为 sidebar:state
,它保存当前的开/关状态。这个 cookie 会在后续页面加载时读取,并恢复侧边栏的状态。
要在 Next.js 中持久化侧边栏状态,可以在 app/layout.tsx
中像这样设置 SidebarProvider
:
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>
)
}
You can change the name of the cookie by updating the SIDEBAR_COOKIE_NAME
variable in sidebar.tsx
.
const SIDEBAR_COOKIE_NAME = "sidebar:state"
Sidebar
The main Sidebar
component used to render a collapsible sidebar.
import { Sidebar } from "@/components/ui/sidebar"
export function AppSidebar() {
return <Sidebar />
}
Props
Property | Type | Description |
---|---|---|
side | left or right | The side of the sidebar. |
variant | sidebar , floating , or inset | The variant of the sidebar. |
collapsible | offcanvas , icon , or none | Collapsible state of the sidebar. |
side
Use the side
prop to change the side of the sidebar.
Available options are left
and right
.
import { Sidebar } from "@/components/ui/sidebar"
export function AppSidebar() {
return <Sidebar side="left | right" />
}
variant
Use the variant
prop to change the variant of the sidebar.
Available options are sidebar
, floating
and inset
.
import { Sidebar } from "@/components/ui/sidebar"
export function AppSidebar() {
return <Sidebar variant="sidebar | floating | inset" />
}
Note: If you use the inset
variant, remember to wrap your main content
in a SidebarInset
component.
<SidebarProvider>
<Sidebar variant="inset" />
<SidebarInset>
<main>{children}</main>
</SidebarInset>
</SidebarProvider>
collapsible
Use the collapsible
prop to make the sidebar collapsible.
Available options are offcanvas
, icon
and none
.
import { Sidebar } from "@/components/ui/sidebar"
export function AppSidebar() {
return <Sidebar collapsible="offcanvas | icon | none" />
}
Prop | Description |
---|---|
offcanvas | A collapsible sidebar that slides in from the left or right. |
icon | A sidebar that collapses to icons. |
none | A non-collapsible sidebar. |
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()
}
Property | Type | Description |
---|---|---|
state | expanded or collapsed | The current state of the sidebar. |
open | boolean | Whether the sidebar is open. |
setOpen | (open: boolean) => void | Sets the open state of the sidebar. |
openMobile | boolean | Whether the sidebar is open on mobile. |
setOpenMobile | (open: boolean) => void | Sets the open state of the sidebar on mobile. |
isMobile | boolean | Whether the sidebar is on mobile. |
toggleSidebar | () => void | Toggles the sidebar. Desktop and mobile. |
SidebarHeader
Use the SidebarHeader
component to add a sticky header to the sidebar.
The following example adds a <DropdownMenu>
to the SidebarHeader
.
<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
Use the SidebarFooter
component to add a sticky footer to the sidebar.
The following example adds a <DropdownMenu>
to the SidebarFooter
.
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
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
Use the SidebarGroup
component to create a section within the sidebar.
A SidebarGroup
has a SidebarGroupLabel
, a SidebarGroupContent
and an optional SidebarGroupAction
.
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
To make a SidebarGroup
collapsible, wrap it in a 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>
)
}
Note: We wrap the CollapsibleTrigger
in a SidebarGroupLabel
to render
a button.
SidebarGroupAction
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>
)
}
SidebarMenu
The SidebarMenu
component is used for building a menu within a SidebarGroup
.
A SidebarMenu
component is composed of SidebarMenuItem
, SidebarMenuButton
, <SidebarMenuAction />
and <SidebarMenuSub />
components.
Here's an example of a SidebarMenu
component rendering 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
The SidebarMenuButton
component is used to render a menu button within a SidebarMenuItem
.
Link or Anchor
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
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
Use the isActive
prop to mark a menu item as active.
<SidebarMenuButton asChild isActive>
<a href="#">Home</a>
</SidebarMenuButton>
SidebarMenuAction
The SidebarMenuAction
component is used to render a menu action within a SidebarMenuItem
.
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>
DropdownMenu
Here's an example of a SidebarMenuAction
component rendering a DropdownMenu
.
<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
The SidebarMenuSub
component is used to render a submenu within a SidebarMenu
.
Use <SidebarMenuSubItem />
and <SidebarMenuSubButton />
to render a submenu item.
<SidebarMenuItem>
<SidebarMenuButton />
<SidebarMenuSub>
<SidebarMenuSubItem>
<SidebarMenuSubButton />
</SidebarMenuSubItem>
<SidebarMenuSubItem>
<SidebarMenuSubButton />
</SidebarMenuSubItem>
</SidebarMenuSub>
</SidebarMenuItem>
Collapsible SidebarMenu
To make a SidebarMenu
component collapsible, wrap it and the SidebarMenuSub
components in a Collapsible
.
<SidebarMenu>
<Collapsible defaultOpen className="group/collapsible">
<SidebarMenuItem>
<CollapsibleTrigger asChild>
<SidebarMenuButton />
</CollapsibleTrigger>
<CollapsibleContent>
<SidebarMenuSub>
<SidebarMenuSubItem />
</SidebarMenuSub>
</CollapsibleContent>
</SidebarMenuItem>
</Collapsible>
</SidebarMenu>
SidebarMenuBadge
The SidebarMenuBadge
component is used to render a badge within a SidebarMenuItem
.
<SidebarMenuItem>
<SidebarMenuButton />
<SidebarMenuBadge>24</SidebarMenuBadge>
</SidebarMenuItem>
SidebarMenuSkeleton
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
The SidebarSeparator
component is used to render a separator within a Sidebar
.
<Sidebar>
<SidebarHeader />
<SidebarSeparator />
<SidebarContent>
<SidebarGroup />
<SidebarSeparator />
<SidebarGroup />
</SidebarContent>
</Sidebar>
SidebarTrigger
Use the SidebarTrigger
component to render a button that toggles the sidebar.
The SidebarTrigger
component must be used within a SidebarProvider
.
<SidebarProvider>
<Sidebar />
<main>
<SidebarTrigger />
</main>
</SidebarProvider>
Custom Trigger
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
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 Server Components
Here's an example of a SidebarMenu
component rendering a list of projects using 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>
)
}
function AppSidebar() {
return (
<Sidebar>
<SidebarContent>
<SidebarGroup>
<SidebarGroupLabel>Projects</SidebarGroupLabel>
<SidebarGroupContent>
<React.Suspense fallback={<NavProjectsSkeleton />}>
<NavProjects />
</React.Suspense>
</SidebarGroupContent>
</SidebarGroup>
</SidebarContent>
</Sidebar>
)
}
SWR and React Query
You can use the same approach with SWR or react-query.
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>
)
}
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
Use the open
and onOpenChange
props to control the sidebar.
export function AppSidebar() {
const [open, setOpen] = React.useState(false)
return (
<SidebarProvider open={open} onOpenChange={setOpen}>
<Sidebar />
</SidebarProvider>
)
}
Theming
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.
- Styling an element based on the sidebar collapsible state. The following will hide the
SidebarGroup
when the sidebar is inicon
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>
You can find more tips on using states for styling in this Twitter thread.
Changelog
2024-10-30 Cookie handling in setOpen
- #5593 - Improved setOpen callback logic in
<SidebarProvider>
.
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 Fixed text-sidebar-foreground
- #5491 - Moved
text-sidebar-foreground
from<SidebarProvider>
to<Sidebar>
component.
2024-10-20 Typo in useSidebar
hook.
Fixed typo in useSidebar
hook.
- throw new Error("useSidebar must be used within a Sidebar.")
+ throw new Error("useSidebar must be used within a SidebarProvider.")