Skip to content

SidePanel

8pt grid sizing table for comfortable density.

Default

Usage

tsx
import { SidePanel } from '@tryvienna/ui'

<div className="flex h-[600px] bg-background">
  <SidePanel
    sections={sampleSections}
    selectedId={selectedId}
    onSelect={(id) => setSelectedId(id)}
    toggleShortcutKeys={['⌘', 'B']}
    header={<div className="px-4 py-3 text-sm font-semibold text-foreground">My App</div>}
    footer={<div className="px-4 py-3 text-xs text-muted-foreground">v1.0.0</div>}
  />
  <div className="flex-1 p-8">
    <p className="text-sm text-muted-foreground">Selected: {selectedId}</p>
  </div>
</div>

Examples

Default

Default
tsx
<div className="flex h-[600px] bg-background">
  <SidePanel
    sections={sampleSections}
    selectedId={selectedId}
    onSelect={(id) => setSelectedId(id)}
    toggleShortcutKeys={['⌘', 'B']}
    header={<div className="px-4 py-3 text-sm font-semibold text-foreground">My App</div>}
    footer={<div className="px-4 py-3 text-xs text-muted-foreground">v1.0.0</div>}
  />
  <div className="flex-1 p-8">
    <p className="text-sm text-muted-foreground">Selected: {selectedId}</p>
  </div>
</div>

Compact

Compact
tsx
<div className="flex h-[600px] bg-background">
  <SidePanel
    sections={sampleSections}
    selectedId={selectedId}
    onSelect={(id) => setSelectedId(id)}
    density="compact"
    header={<div className="px-3 py-2 text-xs font-semibold text-foreground">Compact Mode</div>}
  />
  <div className="flex-1 p-8">
    <p className="text-sm text-muted-foreground">Selected: {selectedId}</p>
  </div>
</div>

Collapsed

Collapsed
tsx
<div className="flex h-[600px] bg-background">
  <SidePanel
    sections={sampleSections}
    selectedId={selectedId}
    onSelect={(id) => setSelectedId(id)}
    collapsed={collapsed}
    onCollapsedChange={setCollapsed}
    toggleShortcutKeys={['⌘', 'B']}
  />
  <div className="flex-1 p-8">
    <p className="text-sm text-muted-foreground">
      Sidebar is {collapsed ? 'collapsed' : 'expanded'}. Click the glass pill or press ⌘B.
    </p>
  </div>
</div>

Right Panel

Right Panel
tsx
<div className="flex h-[600px] bg-background">
  <div className="flex-1 p-8">
    <p className="text-sm text-muted-foreground">
      Right panel is {collapsed ? 'collapsed' : 'expanded'}. Selected: {selectedId}
    </p>
  </div>
  <SidePanel
    side="right"
    sections={sampleSections}
    selectedId={selectedId}
    onSelect={(id) => setSelectedId(id)}
    collapsed={collapsed}
    onCollapsedChange={setCollapsed}
    toggleShortcutKeys={['⌘', '\\']}
  />
</div>

Three Column

Three Column
tsx
<div className="flex h-[600px] bg-background">
  <SidePanel
    sections={sampleSections}
    selectedId={selectedId}
    onSelect={(id) => setSelectedId(id)}
    collapsed={leftCollapsed}
    onCollapsedChange={setLeftCollapsed}
    toggleShortcutKeys={['⌘', 'B']}
    header={<div className="px-4 py-3 text-sm font-semibold text-foreground">Navigation</div>}
  />
  <div className="flex flex-1 items-center justify-center">
    <p className="text-sm text-muted-foreground">Selected: {selectedId}</p>
  </div>
  <SidePanel
    side="right"
    sections={sampleSections}
    collapsed={rightCollapsed}
    onCollapsedChange={setRightCollapsed}
    toggleShortcutKeys={['⌘', '\\']}
    header={<div className="px-4 py-3 text-sm font-semibold text-foreground">Details</div>}
  />
</div>

Empty Section

Empty Section
tsx
{
const emptySection: NavSectionData[] = [
  {
    id: 'empty',
    label: 'Empty Section',
    items: [],
    emptyState: {
      message: 'No items yet',
      actionLabel: 'Create one',
      onAction: fn('create'

Variants

NameOptionsDefault
densitycomfortable | compactcomfortable
selectedtrue | falsefalse
hoveredtrue | falsefalse

API Reference

SidePanel

PropTypeDefaultDescription
sectionsNavSectionData&lt;T&gt;[]-
headerReactNode-
sideNavSide-Which side of the layout the sidebar sits on. Affects border, resize handle, and pill positioning.
widthnumber-
minWidthnumber-
maxWidthnumber-
onWidthChange(width: number) =&gt; void-
selectedIdstring-
onSelect(id: string, item: NavItemData&lt;T&gt;) =&gt; void-
footerReactNode-
selectionColorstring-
collapsedboolean-
defaultCollapsedboolean-
onCollapsedChange(collapsed: boolean) =&gt; void-
toggleShortcutKeysstring[]-
expandedNavExpansionState-
defaultExpandedNavExpansionState-
onExpandedChange(state: NavExpansionState) =&gt; void-
densityNavDensity-
horizontalScrollboolean-
'data-testid'string-

Data Attributes

Componentdata-slot
SidePanel"side-panel"