Skip to content
← Inventory

Sidebar

The sidebar shell. Reads open/collapsed state from {@link useSidebar}, so it must render inside a {@link SidebarProvider}. Adapts by viewport and collapsible: an animated docked shell on desktop, a slide-in Sheet on mobile, or a static column when collapsible="none".

Materia

v2.4.0

Usage

import { CONTENT_COLUMN_CLASS, HEADER_HEIGHT, Sidebar, SIDEBAR_COOKIE_MAX_AGE, SIDEBAR_COOKIE_NAME, SIDEBAR_KEYBOARD_SHORTCUT, SIDEBAR_TRANSITION, SIDEBAR_WIDTH, SIDEBAR_WIDTH_COOKIE_NAME, SIDEBAR_WIDTH_DEFAULT_PX, SIDEBAR_WIDTH_ICON, SIDEBAR_WIDTH_MAX_PX, SIDEBAR_WIDTH_MIN_PX, SIDEBAR_WIDTH_MOBILE, sidebarAnatomy, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupAction, SidebarGroupContent, SidebarGroupLabel, SidebarHeader, SidebarInput, SidebarInset, SidebarLayoutHeader, SidebarMenu, SidebarMenuAction, SidebarMenuBadge, SidebarMenuButton, SidebarMenuItem, SidebarMenuLabel, SidebarMenuSkeleton, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, SidebarMenuSubScrollArea, SidebarProvider, SidebarRail, SidebarSeparator, SidebarTrigger, useSidebar, useSidebarResize } from "@desk/ui/components/sidebar";

Best practices

  • Render Sidebar inside a SidebarProvider — it reads open/collapsed state from useSidebar and cannot work outside one.

  • Choose collapsible deliberately: offcanvas slides fully away, icon shrinks to a rail, none is a static column that never adapts to the mobile Sheet.

Props

Sidebar

PropTypeDefaultDescription
childrenReact.ReactNode
side"left" | "right""left"

Edge the sidebar docks to.

variant"inset" | "sidebar" | "floating""sidebar"

Shell style: standard, floating (inset card), or inset (offset content).

collapsible"none" | "icon" | "offcanvas""offcanvas"

Collapse behavior: slide off-canvas, shrink to icon rail, or never collapse.

resizablebooleanfalse

Show a drag handle on the sidebar's inner edge to resize its expanded width (desktop only). Width is clamped, cookie-persisted, and dragging past the collapse threshold magnetically snaps to collapsed.

SidebarGroupAction

PropTypeDefaultDescription
tone"neutral" | "brand" | "danger" | null | undefined
radius"rounded" | "square" | "full" | null | undefined
squareboolean | null | undefined
emphasis"link" | "outline" | "solid" | "ghost" | "soft" | "transparent" | null | undefined
asInputboolean | null | undefined
align"center" | "end" | "start" | null | undefined
pressedboolean | null | undefined
sizeButtonSizeProp"base"

Size token; icon-* variants produce a square icon-only button. Also accepts a responsive object keyed by viewport breakpoints and/or @-prefixed container queries — e.g. { base: "sm", md: "base", "@sm": "lg" }.

asChildbooleanfalse

Merge props and styling onto the single child element via Slot.

loadingboolean | undefinedfalse

Show a spinner and disable interaction.

loadingLabelstring | undefined

Label shown in place of children while loading.

iconIconComponent | undefined

Leading icon (Lucide or SVG component); with no children it becomes an icon-only button.

iconClassNamestring | undefined

Extra classes for the leading icon.

suffixIconIconComponent | undefined

Trailing icon (Lucide or SVG component) rendered at the end.

suffixIconClassNamestring | undefined

Extra classes for the trailing icon.

dotstring | undefined

CSS colour for a status dot; empty/undefined renders no dot.

dotPlacement"end" | "start" | undefined"start"

Dot position relative to content.

expandableboolean | undefinedfalse

Icon-only at rest; expands on hover/focus-visible to reveal the label to the right of the icon. Collapsed geometry equals the matching icon-* size, expanded equals the text button of that size — so pass a text size (sm/base/lg) OR its icon twin (icon-sm …); both resolve identically. Requires both icon and children; ignored with asChild or square. The label stays in the DOM in both states (stable accessible name).

focusedboolean | undefined

Force the focus ring on — for documentation/testing only.

hoveredboolean | undefined

Force the hover state on — for documentation/testing only.

testIdstring
showWhenCollapsedboolean

Show the action button even when sidebar is collapsed

SidebarGroupLabel

PropTypeDefaultDescription
asChildboolean

SidebarInput

PropTypeDefaultDescription
testIdstring
radius"rounded" | "square" | "full" | null | undefined
sizeResponsiveSize"xl" (48px)

Field size — a single token or a per-breakpoint object like { base: "sm", md: "lg" }.

hasErrorboolean

Force error styling; overrides invalid state inherited from an ancestor Field.

focusedboolean

Force focus ring display (for documentation/testing)

SidebarLayoutHeader

PropTypeDefaultDescription
rightOffsetstring

Right padding when sidepanel or other overlay is open

SidebarMenuAction

PropTypeDefaultDescription
asChildboolean

Render the child element as the button (Radix Slot).

showOnHoverbooleanfalse

Reveal only on row hover/focus (or when open) instead of always.

SidebarMenuButton

PropTypeDefaultDescription
asChildboolean

Render the child element as the button (Radix Slot), e.g. wrapping a <Link>.

activeboolean

Marks the row as the current/selected item (sets data-active).

tooltipstring | (import("@radix-ui/react-tooltip").TooltipContentProps & React.RefAttributes<HTMLDivElement>)

Tooltip content shown only when the sidebar is collapsed; also becomes the collapsed aria-label.

tooltipOpenboolean

Control tooltip visibility. Use false to hide tooltip (e.g., when a dropdown is open).

size"base" | "2xs" | "xs" | "sm" | "lg" | "xl" | "2xl" | "3xl"
variant"input" | "default" | "outline"
iconIconComponent
collapsedIconIconComponent

Icon to show when sidebar is collapsed (overrides icon)

collapsedContentReact.ReactNode

Custom content to show when sidebar is collapsed (e.g., Avatar). Takes precedence over collapsedIcon.

suffixIconIconComponent
forceExpandedboolean

Keep label/suffix visible even when the sidebar provider is collapsed.

kbdstring[]
childrenReact.ReactNode

SidebarMenuLabel

PropTypeDefaultDescription
delaynumber0

Delay (seconds) before the expand/collapse fade, for staggering labels.

SidebarMenuSkeleton

PropTypeDefaultDescription
showIconbooleanfalse

Also render a leading icon placeholder.

indexnumber

Index for deterministic width (prevents SSR hydration mismatch)

SidebarMenuSubButton

PropTypeDefaultDescription
kbdstring[] | undefined

Keyboard shortcut keys to display (e.g., ["⌘", "C"]). Ignored if suffixIcon is provided.

childrenstring | number | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | undefined

Text label for the menu item. Use icon prop for icons, not children. When using asChild, pass a single React element.

asChildboolean | undefined

Render as child element using Slot

variant"input" | "default" | "outline" | null | undefined
tone"neutral" | "danger" | null | undefined
insetboolean | null | undefined
radius"rounded" | "square" | "full" | null | undefined
size"base" | "2xs" | "xs" | "sm" | "lg" | "xl" | "2xl" | "3xl" | null | undefined
loadingboolean | undefined

Show loading spinner in place of icon

activeboolean | undefined

Whether the item is in an active/selected state

indicatorReact.ReactNode

Indicator element for checkbox/radio items (absolutely positioned on left). Automatically enables inset.

checkedboolean | undefined

Checked state. Renders the selectionMode indicator inline. When undefined, no indicator renders.

suffixIconLucideIcon | React.ComponentType<React.SVGProps<SVGSVGElement>> | undefined

Icon to display at the end (e.g., checkmark, chevron). Takes precedence over kbd.

avatarReact.ReactNode

Avatar element to display at the start (takes precedence over icon and dot)

suffixReact.ReactNode

Content to display at the end after suffixIcon/kbd (e.g., custom content)

activeIndicator"none" | "dot" | "check" | undefined

Visual indicator for active state. "dot" shows grey dot normally, green when active. "check" shows green checkmark only when active.

iconClassNamestring

Additional className for the icon

selectionMode"checkbox" | "radio" | undefined

Selection visual: "checkbox" renders Checkbox, "radio" renders radio circle. Defaults to "checkbox" when checked is set.

kbdTone"neutral" | "brand" | "danger" | null | undefined

Tone for kbd elements. Options: "neutral" (default), "brand", "danger".

kbdEmphasis"outline" | "solid" | "ghost" | "soft" | null | undefined

Emphasis for kbd elements. Options: "solid" (default), "soft", "outline", "ghost".

dotboolean | "neutral" | "brand" | "danger" | "warning" | "success" | "info"

Dot indicator in the left column (takes precedence over icon): true for a neutral dot, or a {@link Tone} to tint it.

iconIconComponent

Icon to display in the left icon column

SidebarMenuSubScrollArea

PropTypeDefaultDescription
fadebooleanfalse

Add a bottom gradient fade hinting at scrollable overflow.

maxHeight"none" | "dropdown""none"

Cap the height: unconstrained, or clamped to the shared dropdown max.

SidebarProvider

PropTypeDefaultDescription
defaultOpenbooleantrue

Initial open state when uncontrolled.

defaultWidthnumber248

Initial expanded width in px, typically read from the width cookie server-side so the resized width is applied before paint (no flash).

openboolean

Controlled open state — pair with onOpenChange.

onOpenChange(open: boolean) => void

Called with the next open state on toggle; required for controlled use.

SidebarSeparator

PropTypeDefaultDescription
variant"strong" | "default" | "muted" | "accent""default"

Visual weight of the separator line.

showBorderboolean

Whether to show the border line. Defaults to true.

SidebarTrigger

PropTypeDefaultDescription
asChildboolean | undefinedfalse

Merge props and styling onto the single child element via Slot.

tone"neutral" | "brand" | "danger" | null | undefined
radius"rounded" | "square" | "full" | null | undefined
sizeButtonSizeProp"base"

Size token; icon-* variants produce a square icon-only button. Also accepts a responsive object keyed by viewport breakpoints and/or @-prefixed container queries — e.g. { base: "sm", md: "base", "@sm": "lg" }.

dotstring | undefined

CSS colour for a status dot; empty/undefined renders no dot.

loadingboolean | undefinedfalse

Show a spinner and disable interaction.

squareboolean | null | undefined
emphasis"link" | "outline" | "solid" | "ghost" | "soft" | "transparent" | null | undefined
asInputboolean | null | undefined
align"center" | "end" | "start" | null | undefined
pressedboolean | null | undefined
testIdstring
suffixIconIconComponent | undefined

Trailing icon (Lucide or SVG component) rendered at the end.

loadingLabelstring | undefined

Label shown in place of children while loading.

iconClassNamestring | undefined

Extra classes for the leading icon.

suffixIconClassNamestring | undefined

Extra classes for the trailing icon.

dotPlacement"end" | "start" | undefined"start"

Dot position relative to content.

expandableboolean | undefinedfalse

Icon-only at rest; expands on hover/focus-visible to reveal the label to the right of the icon. Collapsed geometry equals the matching icon-* size, expanded equals the text button of that size — so pass a text size (sm/base/lg) OR its icon twin (icon-sm …); both resolve identically. Requires both icon and children; ignored with asChild or square. The label stays in the DOM in both states (stable accessible name).

focusedboolean | undefined

Force the focus ring on — for documentation/testing only.

hoveredboolean | undefined

Force the hover state on — for documentation/testing only.

iconIconComponent

Icon to display. Defaults to PanelLeftCloseIcon.

Also exports

  • constCONTENT_COLUMN_CLASS
  • constHEADER_HEIGHT
  • constSIDEBAR_COOKIE_MAX_AGE
  • constSIDEBAR_COOKIE_NAME
  • constSIDEBAR_KEYBOARD_SHORTCUT
  • constSIDEBAR_TRANSITION
  • constSIDEBAR_WIDTH
  • constSIDEBAR_WIDTH_COOKIE_NAME
  • constSIDEBAR_WIDTH_DEFAULT_PX
  • constSIDEBAR_WIDTH_ICON
  • constSIDEBAR_WIDTH_MAX_PX
  • constSIDEBAR_WIDTH_MIN_PX
  • constSIDEBAR_WIDTH_MOBILE
  • constsidebarAnatomy
  • componentSidebarContent
  • componentSidebarFooter
  • componentSidebarGroup
  • componentSidebarGroupContent
  • componentSidebarHeader
  • componentSidebarInset
  • componentSidebarMenu
  • componentSidebarMenuBadge
  • componentSidebarMenuItem
  • componentSidebarMenuSub
  • componentSidebarMenuSubItem
  • componentSidebarRail
  • constuseSidebar
  • constuseSidebarResize

Anatomy

SidebarProvider

sidebar-wrapper

Provider wrapper managing sidebar state and layout

Sidebar

sidebar

The collapsible navigation panel

SidebarHeader

sidebar-header

Top region for branding or search

SidebarContent

sidebar-content

Scrollable main region holding menus and groups

SidebarMenu

sidebar-menu

List of navigation entries

SidebarMenuItem

sidebar-menu-item

Single menu entry

SidebarMenuButton

sidebar-menu-button

Interactive navigation link

SidebarFooter

sidebar-footer

Bottom region for account or secondary actions

SidebarTrigger

sidebar-trigger

Toggle that opens and closes the sidebar

SidebarInset

sidebar-inset

Main content area offset beside the sidebar

Composition