Back to Shark UI

Sidebar

docs/components/sidebar

latest17.2 KB
Original Source

Sections

Components

Utilities

Forms

Hooks

Sidebar

Copy Markdown

A sidebar for navigation and app structure.

DocsAPI

Embedded content

For full-page examples that wire the sidebar:

Browse the Sidebar Components (soon).

Installation#

CLIManual

pnpmbunnpmyarn

pnpm dlx shadcn@latest add @shark/sidebar

Anatomy#

SidebarProvider
├── Sidebar
│ ├── SidebarHeader
│ ├── SidebarContent
│ │ └── SidebarGroup
│ │ ├── SidebarGroupLabel
│ │ ├── SidebarGroupAction
│ │ ├── SidebarGroupContent
│ │ └── SidebarMenu
│ │ ├── SidebarMenuItem
│ │ │ ├── SidebarMenuButton
│ │ │ ├── SidebarMenuAction
│ │ │ └── SidebarMenuBadge
│ │ └── SidebarMenuSub
│ │ ├── SidebarMenuSubButton
│ │ └── SidebarMenuSubItem
│ ├── SidebarFooter
│ ├── SidebarSeparator
│ └── SidebarInput
├── SidebarTrigger
├── SidebarRail
└── SidebarInset

Structure#

Piecing a Sidebar together usually means:

  • <SidebarProvider> — Owns open/collapsed state, mobile sheet state, and keyboard shortcut handling.
  • <Sidebar> — Fixed (or sheet) column: placement, variant, and collapsible behavior.
  • <SidebarHeader> / <SidebarFooter> — Pin content to the top or bottom of the column.
  • <SidebarContent> — Scrollable middle; optional scrollFade on the inner scroll area.
  • <SidebarGroup> — Labeled section inside the scroll region.
  • <SidebarTrigger> — Icon/control wired to useSidebar().toggleSidebar.
  • <SidebarInset> — Main document column beside the sidebar (required for variant="inset").

Optional helpers: <SidebarRail> (edge hit target), the <SidebarMenu> building blocks (submenus, badges, skeletons, actions)—same roles as in the upstream doc.

<SidebarHeader />

<SidebarGroup />

<SidebarGroup />

<SidebarContent />

<SidebarFooter />

<Sidebar />

Sidebar Anatomy

Usage#

app/layout.tsx keeps the provider at the top level:

app/layout.tsx

import { SidebarProvider, SidebarTrigger } from "@/components/ui/sidebar";
import { AppSidebar } from "@/components/app-sidebar";

export default function Layout({ children }: React.PropsWithChildren) {
  return (
    <SidebarProvider>
      <AppSidebar />
      <main>
        <SidebarTrigger />
        {children}
      </main>
    </SidebarProvider>
  );
}

The sidebar column itself is usually a dedicated module:

components/app-sidebar.tsx

import {
  Sidebar,
  SidebarContent,
  SidebarFooter,
  SidebarGroup,
  SidebarHeader,
} from "@/components/ui/sidebar";

export function AppSidebar() {
  return (
    <Sidebar>
      <SidebarHeader />
      <SidebarContent>
        <SidebarGroup />
        <SidebarGroup />
      </SidebarContent>
      <SidebarFooter />
    </Sidebar>
  );
}

Controlled#

Use the onOpenChange prop to control the sidebar open state.

"use client";

import React from "react";
import { Sidebar, SidebarProvider } from "@/components/ui/sidebar";

export const ControlledLayout = () => {
  const [open, setOpen] = React.useState(false);

  return (
    <SidebarProvider onOpenChange={setOpen} open={open}>
      <Sidebar />
    </SidebarProvider>
  );
}

Theming#

Sidebar uses CSS variables to style the sidebar. See the full palette in Colors.

Variable Reference#

--sidebar — Sidebar background

--sidebar-foreground — Sidebar text

--sidebar-primary — Active item background

--sidebar-accent — Hover and active states

--sidebar-border — Sidebar borders

--sidebar-ring — Focus rings

Learn more about styling in the Styling section.

Styling#

React to collapse mode and peer state with utilities.

<Sidebar collapsible="icon">
  <SidebarContent>
    <SidebarGroup className="group-data-[collapsible=icon]:hidden" />
  </SidebarContent>
</Sidebar>
<SidebarMenuItem>
  <SidebarMenuButton />
  <SidebarMenuAction className="peer-data-[active=true]/menu-button:opacity-100" />
</SidebarMenuItem>

Keyboard shortcut#

The toggle listens for ⌘B on macOS and Ctrl+B elsewhere (SIDEBAR_KEYBOARD_SHORTCUT in source). Match that expectation in shortcuts or help copy.

API Reference#

SidebarProvider#

SidebarProvider must wrap any tree that calls useSidebar or renders Sidebar / SidebarTrigger. It forwards standard div props (including className and style).

NameTypeDescription
defaultOpenbooleanInitial open state on desktop (true by default).
openbooleanControlled open flag.
onOpenChange(open: boolean) => voidFires when the open flag changes.

Width#

Defaults live beside SIDEBAR_WIDTH and SIDEBAR_WIDTH_MOBILE inside the registry file. Override per layout with CSS variables on the provider:

<SidebarProvider
  style={
    {
      "--sidebar-width": "20rem",
      "--sidebar-width-mobile": "20rem",
    } as React.CSSProperties
  }
>
  <Sidebar />
</SidebarProvider>
AttributeDefault
--sidebar-width16rem
--sidebar-width-mobile18rem
--sidebar-width-icon3rem

Primary column component: desktop fixed strip + mobile sheet (via Sheet).

PropertyTypeDescription
placement`"left""right"`
variant`"sidebar""floating"
collapsible`"offcanvas""icon"

Collapsible modes#

ModeBehavior
offcanvasCollapses off-screen; rail can recall it.
iconShrinks to an icon rail.
noneFixed width; no collapse animation.

With variant="inset" , park page content in SidebarInset so padding, radius, and background line up with the inset shell:

<SidebarProvider>
  <Sidebar variant="inset" />
  <SidebarInset>
    <main>{children}</main>
  </SidebarInset>
</SidebarProvider>

useSidebar#

import { useSidebar } from "@/components/ui/sidebar";

export function Example() {
  const {
    state,
    open,
    setOpen,
    openMobile,
    setOpenMobile,
    isMobile,
    toggleSidebar,
  } = useSidebar();
}
PropertyTypeDescription
state`"expanded""collapsed"`
openbooleanDesktop drawer expanded.
setOpen(open: boolean) => voidSet desktop open.
openMobilebooleanMobile sheet visibility.
setOpenMobile(open: boolean) => voidControl the sheet.
isMobilebooleanBreakpoint-derived mobile flag.
toggleSidebar() => voidToggles desktop or mobile as appropriate.

SidebarHeader#

Sticky top region—common pattern: workspace switcher or brand row inside a SidebarMenu.

<Sidebar>
  <SidebarHeader>
    <SidebarMenu>
      <SidebarMenuItem>
        <SidebarMenuButton>
          <span>Select workspace</span>
          <ChevronDown className="ms-auto" />
        </SidebarMenuButton>
      </SidebarMenuItem>
    </SidebarMenu>
  </SidebarHeader>
</Sidebar>

Wire menus or Menu triggers to SidebarMenuButton as needed.

SidebarFooter#

Sticky bottom slot—profile, settings entry, sign-out, etc.

<Sidebar>
  <SidebarFooter>
    <SidebarMenu>
      <SidebarMenuItem>
        <SidebarMenuButton>
          <User2 /> Username
        </SidebarMenuButton>
      </SidebarMenuItem>
    </SidebarMenu>
  </SidebarFooter>
</Sidebar>

SidebarContent#

Wraps scrollable groups. Pass scrollFade when you want a fade on vertical overflow (see component props in source).

<Sidebar>
  <SidebarContent>
    <SidebarGroup />
    <SidebarGroup />
  </SidebarContent>
</Sidebar>
AttributeDefault
--fade-size3rem

SidebarGroup#

A titled block with optional SidebarGroupAction and SidebarGroupContent.

<SidebarGroup>
  <SidebarGroupLabel>Application</SidebarGroupLabel>
  <SidebarGroupAction>
    <Plus /> <span className="sr-only">Add project</span>
  </SidebarGroupAction>
  <SidebarGroupContent />
</SidebarGroup>

Collapsible groups pair with Collapsible. SidebarGroupLabel is a plain label slot—keep the trigger beside it (or fold the pattern into SidebarMenu like the preview at the top of this page):

<Collapsible className="group/collapsible" defaultOpen>
  <SidebarGroup>
    <div className="flex items-center gap-2 px-2">
      <SidebarGroupLabel className="flex-1 px-0">Help</SidebarGroupLabel>
      <CollapsibleTrigger
        className="rounded-md p-1.5 outline-none ring-sidebar-ring focus-visible:ring-2"
        type="button"
      >
        <ChevronDown className="size-4 transition-transform group-data-[state=open]/collapsible:rotate-180" />
      </CollapsibleTrigger>
    </div>
    <CollapsibleContent>
      <SidebarGroupContent />
    </CollapsibleContent>
  </SidebarGroup>
</Collapsible>

SidebarMenu#

Row list inside a group—map data to SidebarMenuItem / SidebarMenuButton.

<SidebarMenu>
  {projects.map((project) => (
    <SidebarMenuItem key={project.name}>
      <SidebarMenuButton asChild>
        <a href={project.url}>
          <project.icon />
          <span>{project.name}</span>
        </a>
      </SidebarMenuButton>
    </SidebarMenuItem>
  ))}
</SidebarMenu>

SidebarMenuButton#

Default renders a Button ; use asChild for links. isActive highlights the active route; tooltip surfaces collapsed labels.

<SidebarMenuButton asChild isActive>
  <a href="#">Home</a>
</SidebarMenuButton>

SidebarMenuAction#

Icon-only or compact action aligned to a row. Use showOnHover to reveal on row hover.

<SidebarMenuItem>
  <SidebarMenuButton asChild>
    <a href="#">
      <Home />
      <span>Home</span>
    </a>
  </SidebarMenuButton>
  <SidebarMenuAction>
    <Plus /> <span className="sr-only">Add project</span>
  </SidebarMenuAction>
</SidebarMenuItem>

SidebarMenuSub#

Nested list hanging off a parent item.

<SidebarMenuItem>
  <SidebarMenuButton />
  <SidebarMenuSub>
    <SidebarMenuSubItem>
      <SidebarMenuSubButton href="#">Child</SidebarMenuSubButton>
    </SidebarMenuSubItem>
  </SidebarMenuSub>
</SidebarMenuItem>

SidebarMenuBadge#

Small count or pill beside a row.

<SidebarMenuItem>
  <SidebarMenuButton />
  <SidebarMenuBadge>24</SidebarMenuBadge>
</SidebarMenuItem>

SidebarMenuSkeleton#

Placeholder rows while async routes or prefs load.

<SidebarMenu>
  {Array.from({ length: 5 }).map((_, index) => (
    <SidebarMenuItem key={index}>
      <SidebarMenuSkeleton />
    </SidebarMenuItem>
  ))}
</SidebarMenu>

SidebarTrigger#

Prebuilt toggle wired to context—drop next to your page title or in a toolbar.

import { useSidebar } from "@/components/ui/sidebar";

export function CustomTrigger() {
  const { toggleSidebar } = useSidebar();
  return <button type="button" onClick={toggleSidebar}>Toggle</button>;
}

Prefer SidebarTrigger when you want the default styling and accessibility bundle.

SidebarRail#

Draggable edge control that expands or collapses the desktop rail—place after header/content/footer inside Sidebar.

<Sidebar>
  <SidebarHeader />
  <SidebarContent>
    <SidebarGroup />
  </SidebarContent>
  <SidebarFooter />
  <SidebarRail />
</Sidebar>

[

Previous page

Sheet ](/docs/components/sheet)[

Next page

Signature Pad ](/docs/components/signature-pad)

On This Page

InstallationAnatomyStructureUsageControlledThemingVariable ReferenceStylingKeyboard shortcutAPI ReferenceSidebarProviderWidthSidebarCollapsible modesuseSidebarSidebarHeaderSidebarFooterSidebarContentSidebarGroupSidebarMenuSidebarMenuButtonSidebarMenuActionSidebarMenuSubSidebarMenuBadgeSidebarMenuSkeletonSidebarTriggerSidebarRail