Sidebar
A collapsible sidebar layout commonly used for application navigation. Built using Box, Column, Row, Icon, Text, and Button components.
Acme Inc
Dashboard
Users
Documents
Settings
John DoeAdmin
Main content area
Source
'use client';
import { createContext, useContext, useState } from 'react';
import { Box, Column, Row, Icon, Text, Button } from '@umami/react-zen';
import { PanelLeft } from 'lucide-react';
const SidebarContext = createContext({
isCollapsed: false,
setCollapsed: () => {},
});
export function useSidebar() {
return useContext(SidebarContext);
}
export function Sidebar({
defaultCollapsed = false,
collapsedWidth = '4rem',
expandedWidth = '14rem',
children,
...props
}) {
const [isCollapsed, setCollapsed] = useState(defaultCollapsed);
return (
<SidebarContext.Provider value={{ isCollapsed, setCollapsed }}>
<Box
height="100%"
backgroundColor="surface-raised"
borderColor="muted"
border="right"
style={{
width: isCollapsed ? collapsedWidth : expandedWidth,
transition: 'width 0.2s ease-in-out',
}}
{...props}
>
<Column height="100%" justifyContent="space-between">
{children}
</Column>
</Box>
</SidebarContext.Provider>
);
}
export function SidebarHeader({ icon, title }) {
const { isCollapsed } = useSidebar();
return (
<Row
padding="4"
gap="3"
alignItems="center"
borderColor="muted"
border="bottom"
justifyContent={isCollapsed ? 'center' : 'flex-start'}
>
{icon && (
<Box
width="8"
height="8"
borderRadius="md"
backgroundColor="primary"
flexShrink="0"
>
{icon}
</Box>
)}
{!isCollapsed && title && <Text weight="semibold">{title}</Text>}
</Row>
);
}
export function SidebarNav({ children }) {
return (
<Column padding="2" gap="1" flexGrow="1">
{children}
</Column>
);
}
export function SidebarItem({ icon, label, isSelected, onClick }) {
const { isCollapsed } = useSidebar();
return (
<Row
paddingY="2"
paddingX="3"
borderRadius="md"
gap="3"
alignItems="center"
justifyContent={isCollapsed ? 'center' : 'flex-start'}
backgroundColor={isSelected ? 'interactive' : undefined}
className={`cursor-pointer ${!isSelected ? 'hover:bg-interactive' : ''}`}
onClick={onClick}
>
<Icon size="sm" color={isSelected ? undefined : 'muted'}>
{icon}
</Icon>
{!isCollapsed && (
<Text color={isSelected ? undefined : 'muted'}>
{label}
</Text>
)}
</Row>
);
}
export function SidebarFooter({ children }) {
return (
<Box padding="4" borderColor="muted" border="top">
{children}
</Box>
);
}
export function SidebarToggle() {
const { isCollapsed, setCollapsed } = useSidebar();
return (
<Button variant="quiet" onPress={() => setCollapsed(!isCollapsed)}>
<Icon style={{ transform: isCollapsed ? 'scaleX(-1)' : undefined }}>
<PanelLeft />
</Icon>
</Button>
);
}Variations
With section dividers
Acme Inc
MAIN
Dashboard
Users
SETTINGS
General
Security
Main content area
Always collapsed (icon-only)
Main content area
Minimal with toggle only
Home
Search
Notifications
Main content area