# Sidebar **Category**: react **URL**: https://ui.darkcode.dev/en/docs/react/components/sidebar **Source**: https://raw.githubusercontent.com/DarkCode-Developers/darkcode-ui/refs/heads/main/apps/docs/content/docs/en/react/components/(navigation)/sidebar.mdx > A responsive sidebar navigation component with collapsible groups, rail mode, icon collapse, resizing, hover-to-peek, search, drag-to-reorder, and mobile sheet support. *** ## Import ```tsx import { Sidebar, useSidebar } from '@darkcode-ui/react'; ``` ### Usage ```tsx "use client"; import {Sidebar} from "@darkcode-ui/react"; import {ChartColumn, Folder, Gear, House, ListUl, Persons, Sparkles} from "@gravity-ui/icons"; export function SidebarDefault() { return (
DarkCode
Dashboard Projects Tasks 8 Team Analytics Settings

Dashboard

); } ``` ### Anatomy Import the Sidebar component and access all parts using dot notation. ```tsx import { Sidebar } from '@darkcode-ui/react'; export default () => ( ); ``` The menu is built on the React Aria [Tree](https://react-spectrum.adobe.com/react-aria/Tree.html) collection, so it ships full keyboard navigation, typeahead, and nested expand/collapse out of the box. `` is responsive: on desktop it renders a fixed panel, and at mobile widths (≤768px) it automatically renders its children inside a slide-in [Drawer](/en/react/components/drawer). ### Complex A full-featured sidebar with teamspaces, favorites, nested menus, and a user footer. ```tsx "use client"; import {Sidebar} from "@darkcode-ui/react"; import {Bell, Code, House, Magnifier, Palette, Star} from "@gravity-ui/icons"; import {Brand, DemoMain, NavItem, UserFooter} from "./shared"; export function SidebarComplex() { return ( } label="Home" /> } label="Search" /> } label="Inbox" /> Teamspaces Engineering Design Favorites } label="Q3 Planning" /> } label="Release Notes" /> ); } ``` ### Compact With User Menu Compact sidebar with a user button at the footer. ```tsx "use client"; import {Button, Sidebar} from "@darkcode-ui/react"; import {Folder, Gear, House, Persons} from "@gravity-ui/icons"; import {Brand, DemoMain, NavItem, UserFooter} from "./shared"; export function SidebarCompactWithUserMenu() { return ( } label="Overview" /> } label="Documents" /> } label="Members" /> } label="Settings" /> ); } ``` ### Meeting Notes Notes-style sidebar with a search field and spaces. Uses `collapsible="offcanvas"`. ```tsx "use client"; import {Button, Sidebar} from "@darkcode-ui/react"; import {Calendar, FileText, Magnifier, Person} from "@gravity-ui/icons"; import {Brand, DemoMain, NavItem, UserFooter} from "./shared"; export function SidebarMeetingNotes() { return ( Spaces } label="All Notes" /> } label="Meetings" /> } label="1:1s" /> ); } ``` ### Agent Hub Agent-focused sidebar combining workspaces, recent chats, and a user footer. ```tsx "use client"; import {Sidebar} from "@darkcode-ui/react"; import {Comment, Sparkles, Wrench} from "@gravity-ui/icons"; import {Brand, DemoMain, NavItem, UserFooter} from "./shared"; export function SidebarAgentHub() { return ( } label="Agents" /> } label="Conversations" /> } label="Tools" /> Recent chats } label="Refactor billing module" /> } label="Generate release notes" /> } label="Triage open issues" /> ); } ``` ### Agent Workspace Workspace sidebar with agent tasks grouped by status, inspired by AI coding tools. ```tsx "use client"; import {Sidebar} from "@darkcode-ui/react"; import {CircleCheck, CircleDashed, Code} from "@gravity-ui/icons"; import {Brand, DemoMain, NavItem, UserFooter} from "./shared"; export function SidebarAgentWorkspace() { return ( darkcode-ui In progress 2 } label="Add Sidebar component" /> } label="Fix tree navigation" /> Done 5 } label="Bundle size budget" /> ); } ``` ### Inset Variant The inset variant uses a transparent sidebar background with a card-like content area. ```tsx "use client"; import {Sidebar} from "@darkcode-ui/react"; import {Folder, Gear, House, Persons} from "@gravity-ui/icons"; import {Brand, DemoMain, NavItem, UserFooter} from "./shared"; export function SidebarInsetVariant() { return ( } label="Dashboard" /> } label="Projects" /> } label="Team" /> } label="Settings" /> ); } ``` ### With Groups Organize menu items into labeled groups separated by dividers. ```tsx "use client"; import {Sidebar} from "@darkcode-ui/react"; import {CreditCard, Folder, Gear, House, Person} from "@gravity-ui/icons"; import {Brand, DemoMain, NavItem} from "./shared"; export function SidebarWithGroups() { return ( Platform } label="Dashboard" /> } label="Projects" /> Account } label="Profile" /> } label="Billing" /> } label="Settings" /> ); } ``` ### Collapsible Groups Use expandable groups for documentation-style navigation with guide lines. ```tsx "use client"; import {Sidebar} from "@darkcode-ui/react"; import {Brand, DemoMain, NavItem} from "./shared"; export function SidebarCollapsibleGroups() { return ( Getting Started Components ); } ``` ### Collapsible Enable `collapsible="icon"` to allow the sidebar to collapse into an icon-only rail. Press `Cmd+B` / `Ctrl+B` to toggle. ```tsx "use client"; import {Sidebar} from "@darkcode-ui/react"; import {Folder, Gear, House, Persons} from "@gravity-ui/icons"; import {Brand, DemoMain, NavItem} from "./shared"; export function SidebarCollapsible() { return ( } label="Dashboard" /> } label="Projects" /> } label="Team" /> } label="Settings" /> ); } ``` ### Reduced Motion Pass `reduceMotion` to `Sidebar.Provider` to disable expand/collapse animations. ```tsx "use client"; import {Sidebar} from "@darkcode-ui/react"; import {Folder, House, Square} from "@gravity-ui/icons"; import {Brand, DemoMain, NavItem} from "./shared"; export function SidebarReducedMotion() { return ( } label="Dashboard" /> Projects } label="Project A" /> } label="Project B" /> ); } ``` ### Floating Variant The floating variant renders the sidebar with rounded corners and a shadow. ```tsx "use client"; import {Sidebar} from "@darkcode-ui/react"; import {Folder, Gear, House, Persons} from "@gravity-ui/icons"; import {Brand, DemoMain, NavItem, UserFooter} from "./shared"; export function SidebarFloatingVariant() { return ( } label="Dashboard" /> } label="Projects" /> } label="Team" /> } label="Settings" /> ); } ``` ### With Avatar Display an organization avatar in the sidebar header. ```tsx "use client"; import {Avatar, Sidebar} from "@darkcode-ui/react"; import {Folder, House, Persons} from "@gravity-ui/icons"; import {DemoMain, NavItem, UserFooter} from "./shared"; export function SidebarWithAvatar() { return (
AC
Acme Corp Pro plan
} label="Dashboard" /> } label="Projects" /> } label="Team" />
); } ``` ### Right Side Position the sidebar on the right by setting `side="right"` on the provider. ```tsx "use client"; import {Sidebar} from "@darkcode-ui/react"; import {Folder, Gear, House, Persons} from "@gravity-ui/icons"; import {Brand, DemoMain, NavItem} from "./shared"; export function SidebarRightSide() { return ( } label="Dashboard" /> } label="Projects" /> } label="Team" /> } label="Settings" /> ); } ``` ### Icon Only A permanently collapsed icon-only sidebar with tooltips on each item. ```tsx "use client"; import type {ReactNode} from "react"; import {Avatar, Sidebar} from "@darkcode-ui/react"; import {ChartColumn, Folder, Gear, House, Persons} from "@gravity-ui/icons"; import {DemoMain} from "./shared"; function IconItem({icon, isCurrent, label}: {icon: ReactNode; label: string; isCurrent?: boolean}) { return ( {icon} {label} ); } export function SidebarIconOnly() { return (
D
} label="Dashboard" /> } label="Projects" /> } label="Team" /> } label="Analytics" /> } label="Settings" />
); } ``` ### Resizable Width Set `resizable` on `Sidebar.Provider` to drag the [rail](#sidebarrail) and resize the sidebar. The width is clamped between `minWidth` and `maxWidth`, and persisted to a `sidebar_width` cookie. ```tsx "use client"; import {Sidebar} from "@darkcode-ui/react"; import {ChartColumn, Folder, House, ListUl, Persons} from "@gravity-ui/icons"; import {Brand, DemoMain, NavItem, UserFooter} from "./shared"; export function SidebarResizableWidth() { return ( Drag the right edge to resize } label="Dashboard" /> } label="Projects" /> } label="Tasks" /> } label="Team" /> } label="Analytics" /> ); } ``` ### Expand On Hover With `collapsible="icon"`, set `expandOnHover` to float the collapsed panel open on hover without shifting the page. ```tsx "use client"; import {Avatar, Sidebar} from "@darkcode-ui/react"; import {ChartColumn, Folder, House, ListUl, Persons} from "@gravity-ui/icons"; import {Brand, DemoMain, NavItem} from "./shared"; export function SidebarExpandOnHover() { return ( } label="Dashboard" /> } label="Projects" /> } label="Tasks" /> } label="Team" /> } label="Analytics" /> JD ); } ``` ### Searchable Add `Sidebar.Search` to filter menu items by their text. Render `Sidebar.MenuEmpty` to show a message when nothing matches. ```tsx "use client"; import {Sidebar} from "@darkcode-ui/react"; import {Bell, ChartColumn, Folder, Gear, House, ListUl, Persons} from "@gravity-ui/icons"; import {Brand, DemoMain, NavItem, UserFooter} from "./shared"; export function SidebarSearchable() { return ( } label="Dashboard" /> } label="Projects" /> } label="Tasks" /> } label="Team" /> } label="Analytics" /> } label="Settings" /> } label="Notifications" /> ); } ``` ### Reorderable Set `allowReorder` and provide an `onReorder` handler on `Sidebar.Menu` to reorder items by drag-and-drop. The menu's order is controlled by your data. ```tsx "use client"; import type {ReactNode} from "react"; import {Sidebar} from "@darkcode-ui/react"; import {ChartColumn, Folder, House, ListUl, Persons} from "@gravity-ui/icons"; import {useState} from "react"; import {Brand, DemoMain, UserFooter} from "./shared"; interface ReorderItem { id: string; icon: ReactNode; label: string; } const initialItems: ReorderItem[] = [ {icon: , id: "dashboard", label: "Dashboard"}, {icon: , id: "projects", label: "Projects"}, {icon: , id: "tasks", label: "Tasks"}, {icon: , id: "team", label: "Team"}, {icon: , id: "analytics", label: "Analytics"}, ]; export function SidebarReorderable() { const [items, setItems] = useState(initialItems); return ( Drag items to reorder { setItems((prev) => { const keys = [...event.keys].map(String); const moving = prev.filter((item) => keys.includes(item.id)); const rest = prev.filter((item) => !keys.includes(item.id)); const targetIndex = rest.findIndex( (item) => item.id === String(event.target.key), ); const insertAt = event.target.dropPosition === "before" ? targetIndex : targetIndex + 1; rest.splice(insertAt < 0 ? rest.length : insertAt, 0, ...moving); return rest; }); }} > {(item: ReorderItem) => ( {item.icon} {item.label} )} ); } ``` ## Keyboard Shortcut By default the sidebar toggles on `Cmd+B` (macOS) or `Ctrl+B` (other platforms). Override it via the `toggleShortcut` prop on `Sidebar.Provider`: ```tsx {/* … */} ``` The combo string joins modifiers with `+`. Recognized modifiers are `mod` (Cmd on macOS, Ctrl elsewhere), `cmd`, `ctrl`, `meta`, `shift`, and `alt`. Finish with a single key (e.g. `"mod+\\"`, `"ctrl+k"`, `"alt+shift+s"`). To disable the shortcut entirely, pass `false` or `null`: ```tsx {/* … */} ``` The handler calls `preventDefault()` when the shortcut matches. If your app owns its own global keyboard map, disable this shortcut and wire the toggle yourself via [`useSidebar`](#usesidebar). ## Persisted State When `Sidebar.Provider` is **uncontrolled** (no `open` prop), it automatically writes the sidebar state to a `sidebar_state` cookie on every toggle. To restore the state across page loads, read that cookie server-side and pass it as `defaultOpen`. ```tsx // app/layout.tsx (Next.js App Router) import { cookies } from "next/headers"; import { Sidebar } from "@darkcode-ui/react"; export default async function Layout({ children }: { children: React.ReactNode }) { const store = await cookies(); const defaultOpen = store.get("sidebar_state")?.value !== "false"; return ( {/* … */} {children} ); } ``` ## Client-Side Routing `Sidebar.MenuItem` supports navigation via the `href` prop. Because React Aria `TreeItem` elements cannot be rendered as `` tags, navigation is handled programmatically through a `navigate` callback on `Sidebar.Provider`. Pass your router's navigation function and add `href` to any item that should navigate: ```tsx "use client"; import { useRouter } from "next/navigation"; function AppSidebar() { const router = useRouter(); return ( Dashboard ); } ``` External URLs (`http://`, `https://`) automatically open in a new tab. For internal links that need a full page reload, set `forceReload`. If no `navigate` function is provided, `href` falls back to `window.location.href`. ## Resizing Set `resizable` to let users drag the [rail](#sidebarrail) to resize the panel. A click on the rail still toggles the sidebar; a drag resizes it. The width is clamped to `minWidth`/`maxWidth` (default `200`–`420`). When uncontrolled, the chosen width is written to a `sidebar_width` cookie. Restore it on the next load by reading the cookie and passing `defaultWidth` — the same pattern as [persisted open state](#persisted-state): ```tsx import { cookies } from "next/headers"; const store = await cookies(); const defaultWidth = Number(store.get("sidebar_width")?.value) || undefined; {/* … */} ``` For full control, pass `width` and `onWidthChange`. ## Active Indicator The current item (`isCurrent`) shows an accent bar. By default (`animateActiveIndicator`), component-initiated navigation (items with `href`) is wrapped in [`document.startViewTransition`](https://developer.mozilla.org/en-US/docs/Web/API/Document/startViewTransition) so the bar morphs to its new position where supported. For fully-controlled `isCurrent`, wrap your own state change in `startViewTransition` to get the same effect. The transition is skipped automatically when `reduceMotion` is set or the user prefers reduced motion. ## Search & Filtering `Sidebar.Search` drives a search query through context; `Sidebar.MenuItem` hides itself when its text doesn't match. Both live anywhere inside `Sidebar.Provider`. Use `Sidebar.MenuEmpty` to render a fallback when no items match. ```tsx {/* …items… */} No results found ``` Filtering matches items that are currently rendered. Items inside a **collapsed** submenu are not rendered by the underlying Tree, so they aren't matched until expanded. Use a flat menu for fully searchable navigation. ## Reordering Set `allowReorder` and an `onReorder` handler on `Sidebar.Menu` to enable drag-and-drop reordering (built on React Aria's [`useDragAndDrop`](https://react-spectrum.adobe.com/react-aria/dnd.html)). Items need stable `id`s, and the order is **controlled** — apply the reorder to your own data in `onReorder`: ```tsx setItems((prev) => reorder(prev, e))} > {(item) => ( {/* … */} )} ``` Keyboard drag-and-drop is supported out of the box via the Tree collection. ## API Reference ### Sidebar.Provider Layout wrapper that provides sidebar context to all children. Wraps both the sidebar and main content. | Prop | Type | Default | Description | |------|------|---------|-------------| | `open` | `boolean` | — | Controlled open/expanded state. | | `defaultOpen` | `boolean` | `true` | Initial open state (uncontrolled). | | `onOpenChange` | `(open: boolean) => void` | — | Callback when open state changes. | | `side` | `"left" \| "right"` | `"left"` | Which side the sidebar is on. | | `variant` | `"sidebar" \| "floating" \| "inset"` | `"sidebar"` | Visual style variant. | | `collapsible` | `"icon" \| "offcanvas" \| "none"` | `"icon"` | Collapse behavior. | | `navigate` | `(href: string) => void` | — | Programmatic navigation function for client-side routing. | | `reduceMotion` | `boolean` | `false` | Disable expand/collapse animations. | | `animateActiveIndicator` | `boolean` | `true` | Morph the active-item indicator between items via View Transitions. | | `expandOnHover` | `boolean` | `false` | When `collapsible="icon"`, expand to a floating panel on hover. | | `resizable` | `boolean` | `false` | Allow resizing the sidebar by dragging the rail. | | `width` | `number` | — | Controlled width in px. | | `defaultWidth` | `number` | — | Initial width in px (uncontrolled). Falls back to the CSS default. | | `onWidthChange` | `(width: number) => void` | — | Called when the width changes via dragging. | | `minWidth` | `number` | `200` | Minimum width in px when resizable. | | `maxWidth` | `number` | `420` | Maximum width in px when resizable. | | `toggleShortcut` | `string \| false \| null` | `"mod+b"` | Keyboard shortcut that toggles the sidebar. | | `backdrop` | `"blur" \| "opaque" \| "transparent"` | `"blur"` | Backdrop style for the mobile sheet. | ### Sidebar The responsive sidebar panel. Renders an `