Sidebar

Composable navigation sidebar for app shells with collapsible sections, search and filter, tree views with hover actions, and a mobile menu

import {
SidebarProvider,
SidebarLayout,
Sidebar,
SidebarHeader,
SidebarContent,
SidebarFooter,
SidebarGroup,
SidebarGroupLabel,
SidebarMenu,
SidebarMenuItem,
SidebarMenuButton,
SidebarInset,
SidebarTrigger,
} from "@plexui/ui/components/Sidebar";

Examples

App Shell

Basic

collapsible
labelSize

Collapsible Sections

Search and Filter

expand

Tree with Hover Actions

action

Mobile Menu

Search Input

API

Structure

A Sidebar is composed of the following parts:

  • SidebarProvider: Handles collapsible state and provides context to all child components.
  • SidebarLayout: Wrapper for sidebar and main content.
  • Sidebar: The sidebar container.
  • SidebarHeader / SidebarFooter: Sticky at the top and bottom of the sidebar.
  • SidebarContent: Scrollable content area.
  • SidebarGroup: Section within the content, with optional label.
  • SidebarMenu / SidebarMenuItem / SidebarMenuButton: Navigation menu items.
  • SidebarMenuSub / SidebarMenuSubButton: Nested submenu items.
  • SidebarInset: Main content area next to the sidebar.
  • SidebarTrigger: Toggle button for collapsing the sidebar.

Use Cmd+B (Mac) or Ctrl+B (Windows/Linux) to toggle the sidebar with keyboard.

SidebarProvider

Handles sidebar state and provides context to all child components. Wrap your application layout in this provider.

PropTypeDefaultDescription
collapsible"offcanvas" | "icon" | "none""offcanvas"Collapse behavior: offcanvas (drawer on mobile, full collapse on desktop), icon (icon rail), or none
defaultOpenbooleantrueInitial open state (uncontrolled)
openboolean—Controlled open state
onOpenChange(open: boolean) => void—Called when open state changes. Without open the provider keeps its own state and still calls it
classNamestring—Class of the provider's wrapper
styleCSSProperties—Style of the provider's wrapper, e.g. --sidebar-width

The main sidebar container. Renders as an <aside> element.

PropTypeDefaultDescription
variant"sidebar" | "docs""sidebar"Visual variant
side"left" | "right""left"Which side the sidebar is on

SidebarGroup

A section within SidebarContent.

PropTypeDefaultDescription
defaultOpenbooleantrueWhether the group is open initially. A closed group hides its SidebarGroupContent
openboolean—Controlled open state, also exposed as data-state. The group has no toggle of its own: change open from your own control

SidebarGroupLabel

Renders a section label within a SidebarGroup. Supports two size variants.

PropTypeDefaultDescription
size"sm" | "lg""lg"sm: compact, tertiary. lg: larger, primary, more spacing
asChildbooleanfalseRender the single child element as the label

SidebarMenuItem

PropTypeDefaultDescription
expandedboolean—Marks the item expanded, which turns its SidebarMenuChevron. Pair it with open on its SidebarMenuSub

SidebarMenuButton

Renders a menu item button. Use isActive to highlight the current page.

PropTypeDefaultDescription
isActivebooleanfalseHighlight the current page (aria-current="page")
tooltipstring | ReactNode—Label shown on hover when collapsed (icon mode). Hidden on mobile.
asChildbooleanfalseRender the single child element (e.g. a router link) as the button. The button attributes go on the child and its content is wrapped like the button's

SidebarMenuSub

Renders a collapsible submenu container for nested navigation.

PropTypeDefaultDescription
openbooleantrueWhether submenu is expanded. A closed submenu is inert, so its links and buttons leave the tab order and the accessibility tree
hasIconsbooleanfalseAlign child items with parent text that has icons

SidebarMenuSubButton

PropTypeDefaultDescription
isActivebooleanfalseHighlight the current page (aria-current="page")
indent0 | 1 | 2 | 30Nesting level; each level adds 12px of left margin
asChildbooleanfalseRender the single child element (e.g. a router link) as the button

SidebarTrigger

Collapse button. Renders nothing when collapsible="none". Children replace the default icon. An onClick runs before the toggle; call event.preventDefault() in it to cancel the toggle. SidebarMobileMenuButton, the animated hamburger for the mobile menu, handles onClick the same way.

SidebarInput

A search field: Input with a search icon as its start adornment. It takes every Input prop.

SidebarCard

Renders a promotional card in the sidebar footer for CTAs, upgrades, or announcements.

PropTypeDefaultDescription
variant"default" | "elevated""default"Visual variant
dismissiblebooleanfalseShows dismiss button
onDismiss() => void—Callback when dismissed

useSidebar

Hook to access sidebar state and controls from any component within SidebarProvider.

  • state: Current state: "expanded" or "collapsed"
  • open / setOpen: Desktop sidebar open state
  • openMobile / setOpenMobile: Mobile menu open state
  • isMobile: Whether the viewport is mobile
  • collapsible: Current collapsible mode
  • toggleSidebar: Toggle function for both desktop and mobile

Styling

Sidebar reads these component tokens. Override them at any scope to restyle it. SidebarProvider sets the three width tokens on its own element, so change those through its style (or on an element inside it):

  • --sidebar-accent: accent (default light-dark(var(--alpha-08), var(--alpha-12)))
  • --sidebar-background: background (default none)
  • --sidebar-border: border (default var(--color-border))
  • --sidebar-collapse-duration: collapse duration (default 0.3s)
  • --sidebar-footer-shadow: footer shadow
  • --sidebar-foreground: foreground (default var(--color-text))
  • --sidebar-group-label-color: group label color (default var(--color-text-tertiary))
  • --sidebar-gutter: gutter (default 12px)
  • --sidebar-gutter-sm: gutter sm (default var(--control-gutter-2xs))
  • --sidebar-header-height: header height (default var(--control-size-3xl))
  • --sidebar-icon-margin: icon margin (default 0 2px 0 4px)
  • --sidebar-icon-size: icon size (default 20px)
  • --sidebar-icon-wrapper-size: icon wrapper size (default 32px)
  • --sidebar-inset-shadow: inset shadow (default none)
  • --sidebar-menu-item-font-size: menu item font size (default 14px)
  • --sidebar-menu-item-height: menu item height (default 38px)
  • --sidebar-menu-item-height-desktop: menu item height desktop (default 32px)
  • --sidebar-menu-item-line-height: menu item line height (default 20px)
  • --sidebar-menu-item-margin: menu item margin (default 0 0 2px)
  • --sidebar-menu-item-margin-desktop: menu item margin desktop (default 0 0 2px)
  • --sidebar-menu-item-padding: menu item padding (default 0)
  • --sidebar-menu-item-radius: menu item radius (default 8px)
  • --sidebar-menu-sub-max-height: height an open submenu animates to (default 1000px); raise it for long lists, or set none to skip the animation
  • --sidebar-menu-text: menu text (default light-dark(var(--gray-750), var(--gray-850)))
  • --sidebar-menu-text-active: menu text active (default var(--gray-900))
  • --sidebar-mobile-backdrop-color: mobile backdrop color (default light-dark(rgb(0 0 0 / 15%), rgb(0 0 0 / 35%)))
  • --sidebar-mobile-button-radius: mobile button radius (default 8px)
  • --sidebar-mobile-button-size: mobile button size (default 32px)
  • --sidebar-mobile-enter-delay: mobile enter delay (default 0.33s)
  • --sidebar-mobile-enter-opacity-duration: mobile enter opacity duration (default 0.8s)
  • --sidebar-mobile-enter-transform-duration: mobile enter transform duration (default 0.7s)
  • --sidebar-mobile-exit-duration: mobile exit duration (default 0.3s)
  • --sidebar-mobile-gutter: mobile gutter (default 12px)
  • --sidebar-mobile-header-height: mobile header height (default 48px)
  • --sidebar-mobile-icon-size: mobile icon size (default 18px)
  • --sidebar-mobile-line-color: mobile line color (default var(--gray-900))
  • --sidebar-mobile-line-height: mobile line height (default 2px)
  • --sidebar-mobile-line-transition-duration: mobile line transition duration (default 0.2s)
  • --sidebar-mobile-z-index: mobile z index (default 301)
  • --sidebar-transition-duration: transition duration (default 0.3s)
  • --sidebar-width: width (SidebarProvider sets 240px)
  • --sidebar-width-icon: width icon (SidebarProvider sets 64px)
  • --sidebar-width-mobile: width mobile (SidebarProvider sets 288px)
  • --skeleton-background: background (default light-dark(var(--alpha-08), var(--alpha-12)))
  • --skeleton-radius: radius (default var(--radius-md))