Sidebar
Navigation sidebar component for app navigation
Sidebar
The Sidebar component provides the primary navigation for authenticated applications. It displays navigation items, branding, user info, and collapse controls.
Type Signature
interface SidebarProps {
/** Navigation items */
nav: NavItem[]
/** User info for bottom of sidebar */
user?: {
name: string
email: string
avatar?: string
}
/** Branding */
logo?: React.ReactNode
/** Collapsed state */
collapsed?: boolean
/** On collapse toggle */
onCollapse?: () => void
}
interface NavItem {
label: string
href: string
icon?: string
description?: string
children?: NavItem[]
}Usage
const nav = [
{ label: 'Dashboard', href: '/', icon: 'LayoutDashboard' },
{ label: 'API Keys', href: '/keys', icon: 'Key' },
{ label: 'Webhooks', href: '/webhooks', icon: 'Webhook' },
{ label: 'Settings', href: '/settings', icon: 'Settings' },
]
<Sidebar
nav={nav}
user={{
name: 'John Doe',
email: 'john@acme.com',
avatar: 'https://...'
}}
/>Props
nav
Array of navigation items to display. Supports nested items for section grouping.
const nav = [
{
label: 'Dashboard',
href: '/',
icon: 'LayoutDashboard'
},
{
label: 'Developer',
href: '/developer',
icon: 'Code',
children: [
{ label: 'API Keys', href: '/keys', icon: 'Key' },
{ label: 'Webhooks', href: '/webhooks', icon: 'Webhook' },
{ label: 'Logs', href: '/logs', icon: 'FileText' },
]
},
{
label: 'Settings',
href: '/settings',
icon: 'Settings'
}
]user
User information displayed at the bottom of the sidebar.
<Sidebar
nav={nav}
user={{
name: 'John Doe',
email: 'john@acme.com',
avatar: 'https://avatar.example.com/john.jpg'
}}
/>Without avatar:
<Sidebar
nav={nav}
user={{
name: 'John Doe',
email: 'john@acme.com'
// Fallback to initials (JD)
}}
/>logo
Custom branding element displayed at the top of the sidebar.
<Sidebar
nav={nav}
logo={
<img src="/logo.svg" alt="Acme" />
}
/>Or use text:
<Sidebar
nav={nav}
logo={
<span className="font-bold text-lg">Acme</span>
}
/>collapsed
Controls the collapsed state. When true, shows icons only.
<Sidebar
nav={nav}
collapsed={true}
/>onCollapse
Callback when the collapse toggle is clicked.
<Sidebar
nav={nav}
collapsed={isCollapsed}
onCollapse={() => setIsCollapsed(!isCollapsed)}
/>Navigation Patterns
Flat Navigation
Simple list of top-level items:
const nav = [
{ label: 'Dashboard', href: '/', icon: 'LayoutDashboard' },
{ label: 'Projects', href: '/projects', icon: 'Folder' },
{ label: 'Team', href: '/team', icon: 'Users' },
{ label: 'Settings', href: '/settings', icon: 'Settings' },
]Grouped Navigation
Items organized into collapsible sections:
const nav = [
{ label: 'Dashboard', href: '/', icon: 'LayoutDashboard' },
{
label: 'Management',
href: '/manage',
icon: 'FolderOpen',
children: [
{ label: 'Projects', href: '/projects', icon: 'Folder' },
{ label: 'Team', href: '/team', icon: 'Users' },
{ label: 'Clients', href: '/clients', icon: 'Building' },
]
},
{
label: 'Developer',
href: '/dev',
icon: 'Code',
children: [
{ label: 'API Keys', href: '/keys', icon: 'Key' },
{ label: 'Webhooks', href: '/webhooks', icon: 'Webhook' },
]
},
{ label: 'Settings', href: '/settings', icon: 'Settings' },
]Icon-Only (Collapsed)
When collapsed, only icons are visible:
┌───┐
│ □ │ Dashboard
│ 📁│ Projects
│ 👥│ Team
│ ⚙│ Settings
└───┘Expanded with Labels
When expanded, icons + labels + descriptions:
┌──────────────────┐
│ □ Dashboard │
│ Overview │
│ │
│ 📁 Projects │
│ View all │
│ │
│ 👥 Team │
│ Members │
│ │
│ ⚙ Settings │
│ Configure │
└──────────────────┘Common Layouts
Developer App
const nav = [
{ label: 'Overview', href: '/', icon: 'LayoutDashboard' },
{ label: 'API Keys', href: '/keys', icon: 'Key' },
{ label: 'Webhooks', href: '/webhooks', icon: 'Webhook' },
{ label: 'Usage', href: '/usage', icon: 'BarChart' },
{ label: 'Logs', href: '/logs', icon: 'FileText' },
{ label: 'Docs', href: '/docs', icon: 'Book' },
{ label: 'Settings', href: '/settings', icon: 'Settings' },
]Admin App
const nav = [
{ label: 'Dashboard', href: '/', icon: 'LayoutDashboard' },
{
label: 'Collections',
href: '/collections',
icon: 'Database',
children: [
{ label: 'Posts', href: '/posts' },
{ label: 'Pages', href: '/pages' },
{ label: 'Media', href: '/media' },
]
},
{
label: 'Access',
href: '/access',
icon: 'Shield',
children: [
{ label: 'Users', href: '/users' },
{ label: 'Roles', href: '/roles' },
]
},
{ label: 'Settings', href: '/settings', icon: 'Settings' },
]SaaS App
const nav = [
{ label: 'Dashboard', href: '/', icon: 'LayoutDashboard' },
{ label: 'Projects', href: '/projects', icon: 'Folder' },
{ label: 'Team', href: '/team', icon: 'Users' },
{ label: 'Billing', href: '/billing', icon: 'CreditCard' },
{ label: 'Settings', href: '/settings', icon: 'Settings' },
]CRM App
const nav = [
{ label: 'Dashboard', href: '/', icon: 'LayoutDashboard' },
{ label: 'Contacts', href: '/contacts', icon: 'Users' },
{ label: 'Deals', href: '/deals', icon: 'TrendingUp' },
{ label: 'Activities', href: '/activities', icon: 'Calendar' },
{ label: 'Reports', href: '/reports', icon: 'BarChart' },
{ label: 'Settings', href: '/settings', icon: 'Settings' },
]Active State
The Sidebar automatically highlights the current route:
// When at /keys, the "API Keys" item is highlighted
<Sidebar
nav={[
{ label: 'Dashboard', href: '/' },
{ label: 'API Keys', href: '/keys' }, // ← Active
{ label: 'Webhooks', href: '/webhooks' },
]}
/>For nested items, parent items are also highlighted:
// When at /keys, both "Developer" and "API Keys" are highlighted
<Sidebar
nav={[
{ label: 'Dashboard', href: '/' },
{
label: 'Developer', // ← Parent active
href: '/developer',
children: [
{ label: 'API Keys', href: '/keys' }, // ← Active
{ label: 'Webhooks', href: '/webhooks' },
]
},
]}
/>Icons
The Sidebar uses Lucide icon names. Common icons:
| Icon Name | Use Case |
|---|---|
LayoutDashboard | Dashboard/overview |
Folder | Projects/collections |
Users | Team/contacts |
Key | API keys |
Webhook | Webhooks |
BarChart | Analytics/usage |
FileText | Logs/documents |
Settings | Settings |
CreditCard | Billing |
Shield | Security/access |
Code | Developer tools |
Database | Data/collections |
Bell | Notifications |
Calendar | Schedule/events |
See Lucide Icons for the complete list.
User Menu
The user section at the bottom provides:
- Profile - Name, email, avatar
- Account menu - Dropdown with actions
- Status indicator - Online/offline state
<Sidebar
nav={nav}
user={{
name: 'John Doe',
email: 'john@acme.com',
avatar: 'https://...'
}}
/>The user menu includes:
- Profile
- Settings
- Billing (if applicable)
- Help & Support
- Sign Out
Responsive Behavior
Desktop (≥1024px)
Full sidebar with labels:
┌────────────────┐
│ Logo │
├────────────────┤
│ □ Dashboard │
│ 📁 Projects │
│ 👥 Team │
│ ⚙ Settings │
├────────────────┤
│ 👤 John Doe │
└────────────────┘Tablet (768px - 1023px)
Collapsed by default (icons only):
┌───┐
│ ≡ │
├───┤
│ □ │
│ 📁│
│ 👥│
│ ⚙ │
├───┤
│ 👤│
└───┘Mobile (under 768px)
Hidden by default, slides over as drawer:
┌──────────────────────┐
│ ☰ Menu ✕ │
│ │
│ □ Dashboard │
│ 📁 Projects │
│ 👥 Team │
│ ⚙ Settings │
│ │
│ │
│ 👤 John Doe │
└──────────────────────┘Customization
Custom Width
Override the default width (240px):
<Sidebar
className="w-64" // 256px
nav={nav}
/>Custom Styling
Apply custom styles:
<Sidebar
className="bg-slate-900 text-white"
nav={nav}
/>Custom Logo Size
<Sidebar
logo={
<img src="/logo.svg" className="h-8" alt="Acme" />
}
nav={nav}
/>Accessibility
The Sidebar implements accessibility best practices:
- Semantic HTML - Uses
<nav>element - ARIA labels - Descriptive labels for screen readers
- Keyboard navigation - Arrow keys to navigate items
- Focus management - Visible focus indicators
- Collapse state - Announced to screen readers
<nav role="navigation" aria-label="Main navigation">
<button aria-expanded="false" aria-label="Expand sidebar">
{/* Collapse toggle */}
</button>
<ul role="list">
<li>
<a href="/" aria-current="page">Dashboard</a>
</li>
{/* ... */}
</ul>
</nav>Best Practices
Keep Navigation Flat
Avoid deep nesting (max 2 levels):
// Good - 2 levels
const nav = [
{ label: 'Dashboard', href: '/' },
{
label: 'Developer',
children: [
{ label: 'API Keys', href: '/keys' },
{ label: 'Webhooks', href: '/webhooks' },
]
},
]
// Bad - 3+ levels
const nav = [
{
label: 'Developer',
children: [
{
label: 'API',
children: [ // Too deep!
{ label: 'Keys', href: '/keys' },
]
}
]
}
]Use Consistent Icons
Choose icons that clearly represent their function:
// Good - clear icons
{ label: 'Settings', icon: 'Settings' }
{ label: 'Team', icon: 'Users' }
{ label: 'Dashboard', icon: 'LayoutDashboard' }
// Bad - confusing icons
{ label: 'Settings', icon: 'Cloud' } // Unclear
{ label: 'Team', icon: 'Star' } // UnclearLimit Items
Keep navigation focused (5-10 top-level items):
// Good - focused navigation
const nav = [
{ label: 'Dashboard', href: '/' },
{ label: 'Projects', href: '/projects' },
{ label: 'Team', href: '/team' },
{ label: 'Settings', href: '/settings' },
]
// Bad - too many items
const nav = [
{ label: 'Dashboard', href: '/' },
{ label: 'Projects', href: '/projects' },
{ label: 'Tasks', href: '/tasks' },
{ label: 'Files', href: '/files' },
{ label: 'Messages', href: '/messages' },
{ label: 'Calendar', href: '/calendar' },
{ label: 'Team', href: '/team' },
{ label: 'Clients', href: '/clients' },
{ label: 'Invoices', href: '/invoices' },
{ label: 'Reports', href: '/reports' },
{ label: 'Settings', href: '/settings' },
// Too many!
]