SidePanel
8pt grid sizing table for comfortable density.
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
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
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
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
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
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
tsx
{
const emptySection: NavSectionData[] = [
{
id: 'empty',
label: 'Empty Section',
items: [],
emptyState: {
message: 'No items yet',
actionLabel: 'Create one',
onAction: fn('create'Variants
| Name | Options | Default |
|---|---|---|
density | comfortable | compact | comfortable |
selected | true | false | false |
hovered | true | false | false |
API Reference
SidePanel
| Prop | Type | Default | Description |
|---|---|---|---|
sections | NavSectionData<T>[] | - | |
header | ReactNode | - | |
side | NavSide | - | Which side of the layout the sidebar sits on. Affects border, resize handle, and pill positioning. |
width | number | - | |
minWidth | number | - | |
maxWidth | number | - | |
onWidthChange | (width: number) => void | - | |
selectedId | string | - | |
onSelect | (id: string, item: NavItemData<T>) => void | - | |
footer | ReactNode | - | |
selectionColor | string | - | |
collapsed | boolean | - | |
defaultCollapsed | boolean | - | |
onCollapsedChange | (collapsed: boolean) => void | - | |
toggleShortcutKeys | string[] | - | |
expanded | NavExpansionState | - | |
defaultExpanded | NavExpansionState | - | |
onExpandedChange | (state: NavExpansionState) => void | - | |
density | NavDensity | - | |
horizontalScroll | boolean | - | |
'data-testid' | string | - |
Data Attributes
| Component | data-slot |
|---|---|
SidePanel | "side-panel" |