Unified UI

Sidebar

A composable, multi-variant application sidebar with collapsible groups, nested menus, icon-only mode, mobile sheet overlay, and keyboard shortcut toggle. Supports default, floating, and inset layouts.

Overview

The Sidebar is a composable, multi-variant application sidebar system. It supports app sidebars with team/user switchers, docs sidebars with collapsible groups, floating and inset layouts, icon-only collapse mode, mobile sheet overlay, and keyboard shortcut toggle (Ctrl+B / ⌘B).

Main Content

Installation

Install the component via the CLI in one command.

npx @work-rjkashyap/unified-ui add sidebar
pnpm dlx @work-rjkashyap/unified-ui add sidebar
npx @work-rjkashyap/unified-ui add sidebar
bunx @work-rjkashyap/unified-ui add sidebar

If you haven't initialized your project yet, run npx @work-rjkashyap/unified-ui init first. See the CLI docs for details.

Or install the full package

Use this approach if you prefer to install the entire design system as a dependency instead of copying individual components.

npm install @work-rjkashyap/unified-ui
pnpm add @work-rjkashyap/unified-ui
yarn add @work-rjkashyap/unified-ui
bun add @work-rjkashyap/unified-ui

Anatomy

import {
	SidebarProvider,
	Sidebar,
	SidebarTrigger,
	SidebarHeader,
	SidebarContent,
	SidebarFooter,
	SidebarGroup,
	SidebarGroupLabel,
	SidebarGroupAction,
	SidebarGroupContent,
	SidebarMenu,
	SidebarMenuItem,
	SidebarMenuButton,
	SidebarMenuAction,
	SidebarMenuBadge,
	SidebarMenuSub,
	SidebarMenuSubItem,
	SidebarMenuSubButton,
	SidebarMenuSkeleton,
	SidebarSeparator,
	SidebarInput,
	SidebarRail,
	SidebarInset,
} from "@work-rjkashyap/unified-ui";

Architecture

The Sidebar is a compound component composed of multiple parts organized in a strict hierarchy:

<SidebarProvider>               ← State management (collapse, mobile, variant)
  <Sidebar>                     ← The sidebar container
    <SidebarHeader />           ← Sticky top area (logo, team switcher)
    <SidebarContent>            ← Scrollable middle area
      <SidebarGroup>            ← Logical section (collapsible or static)
        <SidebarGroupLabel />   ← Section heading
        <SidebarGroupAction />  ← Action button in group header
        <SidebarGroupContent>   ← Wrapper for items
          <SidebarMenu>         ← Nav list (<ul>)
            <SidebarMenuItem>   ← Nav item (<li>)
              <SidebarMenuButton />   ← Clickable nav button/link
              <SidebarMenuAction />   ← Trailing action (chevron, more)
              <SidebarMenuBadge />    ← Badge/count indicator
              <SidebarMenuSub>        ← Nested sub-menu
                <SidebarMenuSubItem>
                  <SidebarMenuSubButton />
    <SidebarFooter />           ← Sticky bottom area (user, actions)
    <SidebarRail />             ← Thin toggle rail at edge
  <SidebarInset>                ← Main content area (sibling to Sidebar)

Sub-component Reference

Sub-componentPurpose
SidebarProviderContext provider — manages open/collapsed state, variant, mobile detect.
SidebarThe sidebar container with desktop animation and mobile sheet.
SidebarTriggerButton to toggle sidebar open/closed.
SidebarHeaderSticky top area (logo, team switcher, branding).
SidebarContentScrollable middle area for groups and items.
SidebarFooterSticky bottom area (user profile, account actions).
SidebarGroupLogical section container within sidebar content.
SidebarGroupLabelSection heading text (auto-hides in icon-collapse mode).
SidebarGroupActionAction button in group header row (+, −, etc.).
SidebarGroupContentWrapper for the items inside a group.
SidebarMenuNavigation list (<ul>).
SidebarMenuItemSingle item wrapper (<li>).
SidebarMenuButtonClickable nav button with icon, label, tooltip, sizes, variants.
SidebarMenuActionTrailing action button (more options, expand chevron).
SidebarMenuBadgeBadge/count indicator within a menu item.
SidebarMenuSkeletonLoading placeholder for a menu item.
SidebarMenuSubNested sub-menu list with left border indicator.
SidebarMenuSubItemSub-menu item wrapper.
SidebarMenuSubButtonClickable sub-navigation link.
SidebarSeparatorHorizontal divider within the sidebar.
SidebarInputSearch/filter input styled for the sidebar.
SidebarRailThin vertical bar at sidebar edge for toggle affordance.
SidebarInsetMain content area that sits beside the sidebar.

Variants

The sidebar supports three visual variants controlled via the variant prop on SidebarProvider or Sidebar.

Default Variant

The standard bordered sidebar. This is the default.

Navigation
variant="default"

Floating Variant

A rounded sidebar with margin, shadow, and border — appears as a standalone floating panel.

Navigation
variant="floating"

Inset Variant

The sidebar is inset within a parent container. The main content area gets rounded corners and a subtle shadow.

Navigation
variant="inset"

Collapsible Modes

The sidebar supports three collapsible behaviors controlled via the collapsible prop.

Offcanvas (default)

The sidebar slides completely off-screen when collapsed.

collapsible="offcanvas"
Slides off-screen when collapsed.Click the toggle button to try it.

Icon

Collapses to a narrow icon-only width (48px). Labels hide and tooltips appear on hover. This is the mode shown in the second reference image.

Icon-only collapsed mode.Click the toggle button to expand.

None

The sidebar is not collapsible. Good for static documentation sidebars.

Getting Started
collapsible="none"Always expanded, no toggle.

Basic Usage

Wrap your layout in SidebarProvider and place Sidebar alongside SidebarInset for main content.

Navigation
Page Title
Page content goes here

Groups

Use SidebarGroup to organize navigation items into labeled sections.

Static Groups

Platform
Projects
Static groups with labeled sections

Collapsible Groups

Wrap the group label and content with the Collapsible component for expand/collapse behavior. This matches the docs sidebar with +/− toggles pattern.

Docs Content

Group with Action Button

Add an action button to a group header using SidebarGroupAction. Useful for "add" buttons.

Projects
Group with action button+ icon next to "Projects" label

Basic Menu Button

Basic menu buttons

Active State

Mark the current page with isActive:

"Dashboard" is activeisActive highlights the item

Three sizes are available: sm, default, and lg. Use lg for header/footer team or user switchers.

Small
Default
Large
sm, default, and lg sizes

Outline Variant

variant="outline"

With Badge

Show a notification count or indicator next to the item:

  • 24
  • 3
  • 12
Badge counts on menu items

With Action Button

Add a trailing action button (e.g., "more options") that appears on hover:

Projects
Hover items for action buttonshowOnHover reveals the ⋯ icon

Nested Sub-menus

Show hierarchical navigation with nested sub-menus. The sub-menu renders an indented list with a left border line.

Platform
Content

Header with Team Switcher

Use SidebarMenuButton with size="lg" in the header paired with a DropdownMenu for a team/workspace switcher:

Platform
Click the team name to switchDropdownMenu in the header

Use the same pattern in the footer for a user account dropdown:

Platform
Click user to open menuDropdownMenu in the footer

Add a search/filter input at the top of the sidebar:

Getting Started
Search input in the header

Add horizontal dividers between groups:

Platform

Projects
SidebarSeparator between groupsHorizontal divider line

Add a thin toggle rail at the sidebar edge for a hover-to-toggle affordance:

Navigation
SidebarRail at the edgeThin vertical toggle affordance

Place a toggle button in the main content header to expand/collapse the sidebar:

Dashboard
SidebarTrigger in headerClick the toggle button to expand/collapse

Loading State

Show skeleton placeholders while navigation data is loading:

Navigation
Projects
Loading skeleton placeholders

Controlled State

Control the sidebar's open/closed state externally:

const [open, setOpen] = useState(true);

<SidebarProvider open={open} onOpenChange={setOpen}>
	<Sidebar>{/* ... */}</Sidebar>
	<SidebarInset>{/* ... */}</SidebarInset>
</SidebarProvider>;

{
	/* External toggle */
}
<Button onClick={() => setOpen((prev) => !prev)}>Toggle Sidebar</Button>;

useSidebar Hook

Access sidebar state from any descendant component:

function SidebarBrand() {
	const { state, open, toggleSidebar, isMobile } = useSidebar();

	return (
		<div className="flex items-center gap-2">
			<Logo />
			{state === "expanded" && (
				<span className="font-semibold">Acme Inc</span>
			)}
		</div>
	);
}

Hook Return Values

PropertyTypeDescription
state"expanded" | "collapsed"Current visual state of the sidebar.
openbooleanWhether the sidebar is open.
setOpen(open: boolean) => voidSet open state.
openMobilebooleanWhether the mobile sidebar sheet is open.
setOpenMobile(open: boolean) => voidSet mobile sidebar open state.
isMobilebooleanWhether the viewport is mobile (< 768px).
toggleSidebar() => voidToggle the sidebar open/closed.
variant"default" | "floating" | "inset"Current visual variant.
collapsible"offcanvas" | "icon" | "none"Current collapsible mode.
side"left" | "right"Which side the sidebar is on.

Right Side

Place the sidebar on the right side of the layout:

Main contentSidebar on the right side
Activity

Keyboard Shortcut

The sidebar registers Ctrl+B (or ⌘B on macOS) as a global keyboard shortcut to toggle the sidebar. This works automatically when using SidebarProvider.


Full App Layout Example

A complete sidebar layout with team switcher, navigation groups, sub-menus, and user footer.

Full App LayoutTeam switcher • Nav groups • Sub-menus • User footer

Docs Sidebar Layout Example

A static, non-collapsible sidebar suitable for documentation sites:

Docs Content

Props

SidebarProvider

PropTypeDefaultDescription
defaultOpenbooleantrueInitial open state (uncontrolled).
openbooleanControlled open state.
onOpenChange(open: boolean) => voidCalled when open state changes.
variant"default" | "floating" | "inset""default"Visual variant of the sidebar.
collapsible"offcanvas" | "icon" | "none""offcanvas"How the sidebar collapses.
side"left" | "right""left"Which side to place the sidebar.
classNamestringAdditional CSS classes on the wrapper div.
childrenReactNodeShould contain Sidebar + SidebarInset.

All standard <div> HTML attributes are also forwarded.

PropTypeDefaultDescription
side"left" | "right"Provider valueOverrides the provider's side.
variant"default" | "floating" | "inset"Provider valueOverrides the provider's variant.
collapsible"offcanvas" | "icon" | "none"Provider valueOverrides the provider's collapsible mode.
classNamestringAdditional CSS classes.
childrenReactNodeHeader, content, footer, and rail sub-components.

All standard <div> HTML attributes are also forwarded.

SidebarTrigger

PropTypeDefaultDescription
classNamestringAdditional CSS classes.
childrenReactNodeCustom icon (defaults to PanelLeft icon).

All standard <button> HTML attributes are also forwarded.

SidebarHeader / SidebarContent / SidebarFooter

PropTypeDefaultDescription
classNamestringAdditional CSS classes.
childrenReactNodeSection content.

All standard <div> HTML attributes are also forwarded.

SidebarGroup

PropTypeDefaultDescription
classNamestringAdditional CSS classes.
childrenReactNodeGroup label, action, and content.

SidebarGroupLabel

PropTypeDefaultDescription
asChildbooleanfalseRender as a child element (for collapsible triggers).
classNamestringAdditional CSS classes.
childrenReactNodeLabel content.

SidebarGroupAction

PropTypeDefaultDescription
classNamestringAdditional CSS classes.
childrenReactNodeAction content (typically an icon).

All standard <button> HTML attributes are also forwarded.

SidebarGroupContent

PropTypeDefaultDescription
classNamestringAdditional CSS classes.
childrenReactNodeSidebarMenu content.

SidebarMenu

PropTypeDefaultDescription
classNamestringAdditional CSS classes.
childrenReactNodeSidebarMenuItem children.

SidebarMenuItem

PropTypeDefaultDescription
classNamestringAdditional CSS classes.
childrenReactNodeMenu button, action, badge, or sub-menu.

SidebarMenuButton

PropTypeDefaultDescription
isActivebooleanfalseWhether this item is the currently active page.
size"sm" | "default" | "lg""default"Size of the button.
variant"default" | "outline""default"Visual variant.
tooltipstring | ReactNodeTooltip shown when collapsed to icon-only mode.
asChildbooleanfalseRender as a span wrapper (for Radix asChild patterns).
classNamestringAdditional CSS classes.
childrenReactNodeButton content (icon + label).

All standard <button> HTML attributes are also forwarded.

SidebarMenuAction

PropTypeDefaultDescription
showOnHoverbooleanfalseOnly show the action on item hover.
classNamestringAdditional CSS classes.
childrenReactNodeAction content (typically an icon).

All standard <button> HTML attributes are also forwarded.

SidebarMenuBadge

PropTypeDefaultDescription
classNamestringAdditional CSS classes.
childrenReactNodeBadge content (text, count, icon).

SidebarMenuSkeleton

PropTypeDefaultDescription
showIconbooleanfalseWhether to show the icon placeholder.
classNamestringAdditional CSS classes.

SidebarMenuSub

PropTypeDefaultDescription
classNamestringAdditional CSS classes.
childrenReactNodeSidebarMenuSubItem children.

SidebarMenuSubItem

PropTypeDefaultDescription
classNamestringAdditional CSS classes.
childrenReactNodeSub-item content.

SidebarMenuSubButton

PropTypeDefaultDescription
isActivebooleanfalseWhether this sub-item is the currently active page.
size"sm" | "md""md"Size of the sub-button.
classNamestringAdditional CSS classes.

All standard <a> HTML attributes are also forwarded.

SidebarSeparator

PropTypeDefaultDescription
classNamestringAdditional CSS classes.

SidebarInput

PropTypeDefaultDescription
classNamestringAdditional CSS classes.

All standard <input> HTML attributes are also forwarded.

SidebarRail

PropTypeDefaultDescription
classNamestringAdditional CSS classes.

SidebarInset

PropTypeDefaultDescription
classNamestringAdditional CSS classes.
childrenReactNodeMain content (header, page, etc.).

Motion

  • Sidebar width — Animated with CSS-based linear easing (duration: 200ms, ease: [0.25, 0.1, 0.25, 1.0]) when toggling between collapsed and expanded states.
  • Mobile sheet — Slide-in with spring animation (stiffness: 300, damping: 30, mass: 0.8) from the sidebar's side.
  • Mobile overlay — Uses the overlayBackdrop motion preset for a backdrop blur fade.
  • Tooltips — CSS-based animate-in / fade-in / zoom-in for icon-mode tooltips.
  • All animations respect prefers-reduced-motion via Framer Motion's useReducedMotion().

Accessibility

  • The sidebar renders inside a semantic <div> with data-ds-component="sidebar" for styling hooks.
  • SidebarTrigger has aria-label ("Expand sidebar" / "Collapse sidebar") and aria-expanded.
  • Active items use aria-current="page" for assistive technologies.
  • SidebarMenu renders as <ul> and SidebarMenuItem as <li> for proper list semantics.
  • When collapsed to icon-only mode, SidebarMenuButton shows Radix UI tooltips (accessible by keyboard and screen readers).
  • The mobile overlay dismisses the sidebar on click.
  • Keyboard shortcut Ctrl+B / ⌘B toggles the sidebar globally.
  • All interactive elements use the design system focus ring for visible keyboard focus.
  • The SidebarRail has tabIndex={-1} to be click-only (not keyboard-focusable).

Design Tokens

TokenUsage
--sidebarSidebar background color
--sidebar-foregroundSidebar text color
--sidebar-primaryPrimary accent (tooltip background)
--sidebar-primary-foregroundPrimary accent text (tooltip text)
--sidebar-accentActive/hover item background
--sidebar-accent-foregroundActive/hover item text color
--sidebar-borderSidebar borders, rail, separators
--sidebar-ringFocus ring color
--duration-fastHover/focus transition speed

On this page