Sidebar
Playground
TSX
'use client';
import { useId, useState } from 'react';
import {
Avatar,
Button,
Icon,
Sidebar,
SidebarHeader,
SidebarContent,
SidebarFooter,
SidebarTrigger,
} from '@mbsw/ui';
import {
Bell,
Building2,
Blocks,
ChevronDown,
ChevronRight,
CircleCheck,
FileText,
KanbanSquare,
LayoutDashboard,
Palette,
Settings2,
} from 'lucide-react';
export default function Demo() {
const settings = {
"title": "Workspace"
};
const teamList = useId();
const [selected, setSelected] = useState('overview');
const [expanded, setExpanded] = useState<Record<string, boolean>>({
product: true,
design: true,
});
const items = [
{ id: 'overview', label: "Overview", icon: LayoutDashboard },
{ id: 'tasks', label: "Tasks", icon: CircleCheck },
{ id: 'notifications', label: "Notifications", icon: Bell },
];
const teams = [
{
id: 'product',
label: "Product team",
items: [
{ id: 'projects', label: "Projects", icon: KanbanSquare },
{ id: 'documents', label: "Documents", icon: FileText },
],
},
{
id: 'design',
label: "Design team",
items: [
{
id: 'design-system',
label: "Design system",
icon: Blocks,
},
{ id: 'resources', label: "Resources", icon: Palette },
],
},
];
const renderItem = (item: (typeof items)[number], nested = false) => (
<Button
key={item.id}
size="sm"
variant={selected === item.id ? 'solid' : 'ghost'}
tone="secondary"
leadingIcon={item.icon}
style={{
width: '100%',
justifyContent: 'flex-start',
...(nested ? { paddingInlineStart: 21 } : {}),
}}
aria-pressed={selected === item.id}
onClick={() => setSelected(item.id)}
>
{item.label}
</Button>
);
return (
<>
<Sidebar
className="example-sidebar-playground"
aria-label={"Project navigation"}
style={{
height: 340,
background: 'var(--riido-surface-0)',
borderRadius: 'var(--riido-primitive-radius-radius-xs)',
}}
labels={{
collapse: "Collapse sidebar",
expand: "Expand sidebar",
}}
>
<SidebarHeader
style={{
minHeight: 'var(--riido-primitive-spacing-spacing-7)',
paddingInlineStart: 10,
paddingInlineEnd: 4,
}}
>
<div
style={{
display: 'flex',
alignItems: 'center',
gap: 8,
minWidth: 0,
}}
>
<Icon
icon={Building2}
size="sm"
decorative
style={{ flexShrink: 0 }}
/>
<span
style={{
minWidth: 0,
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
fontSize: 13,
fontWeight: 600,
}}
title={settings.title}
>
{settings.title}
</span>
</div>
<SidebarTrigger />
</SidebarHeader>
<SidebarContent>
<nav
aria-label={"Project navigation"}
style={{ display: 'grid', gap: 12 }}
>
<div style={{ display: 'grid', gap: 2 }}>
{items.map((item) => renderItem(item))}
</div>
<section aria-label={"Teams"}>
<h2
style={{
margin: '0 0 4px',
paddingInline: 10,
fontSize: 11,
fontWeight: 500,
color: 'var(--riido-foreground-tertiary)',
}}
>
{"Teams"}
</h2>
{teams.map((team) => (
<div key={team.id}>
<Button
size="sm"
variant="ghost"
tone="secondary"
leadingIcon={expanded[team.id] ? ChevronDown : ChevronRight}
style={{ width: '100%', justifyContent: 'flex-start' }}
aria-expanded={expanded[team.id]}
aria-controls={`${teamList}-${team.id}`}
onClick={() =>
setExpanded((current) => ({
...current,
[team.id]: !current[team.id],
}))
}
>
{team.label}
</Button>
<div
id={`${teamList}-${team.id}`}
hidden={!expanded[team.id]}
>
<div style={{ display: 'grid', gap: 2 }}>
{team.items.map((item) => renderItem(item, true))}
</div>
</div>
</div>
))}
</section>
{renderItem({
id: 'settings',
label: "Settings",
icon: Settings2,
})}
</nav>
</SidebarContent>
<SidebarFooter style={{ paddingBlockEnd: 8 }}>
<div
style={{
display: 'flex',
alignItems: 'center',
gap: 8,
paddingBlockStart: 8,
paddingInline: 10,
borderTop: '1px solid var(--riido-border-divider)',
}}
>
<Avatar
size="sm"
initials="M"
label={"Minji Kim"}
aria-hidden="true"
/>
<span style={{ fontSize: 12 }}>{"Minji Kim"}</span>
</div>
</SidebarFooter>
</Sidebar>
</>
);
}
Usage
Compose the navigation with SidebarHeader, SidebarContent and SidebarFooter. Put one SidebarTrigger inside SidebarHeader; it provides its own icon. Control collapsed with onCollapsedChange, or set the initial state with defaultCollapsed. Set collapse and expand text with labels. Your app owns links, selection and routing.
TSX
'use client';
import {
Sidebar,
SidebarHeader,
SidebarContent,
SidebarTrigger,
} from '@mbsw/ui';
export default function Example() {
return (
<Sidebar
aria-label={"Project navigation"}
style={{ height: 200 }}
labels={{
collapse: "Collapse sidebar",
expand: "Expand sidebar",
}}
>
<SidebarHeader
style={{ minHeight: 'var(--riido-primitive-spacing-spacing-7)' }}
>
<span>{"Workspace"}</span>
<SidebarTrigger />
</SidebarHeader>
<SidebarContent>{"Overview"}</SidebarContent>
</Sidebar>
);
}
The Playground Code tab includes the full example with your current settings. See Installation for the CSS imports.