The Sidebar component provides a comprehensive navigation sidebar with storage meter, user dropdown, and collapsible functionality.
Location: components/sidebar/Sidebar.tsx
Basic Usage
import Sidebar from '@proton/components/components/sidebar/Sidebar';
import SidebarNav from '@proton/components/components/sidebar/SidebarNav';
import SidebarList from '@proton/components/components/sidebar/SidebarList';
import SidebarListItem from '@proton/components/components/sidebar/SidebarListItem';
import { APPS } from '@proton/shared/lib/constants';
const MySidebar = () => {
const [expanded, setExpanded] = useState(false);
return (
<Sidebar
app={APPS.PROTONMAIL}
logo={<Logo />}
expanded={expanded}
onToggleExpand={() => setExpanded(!expanded)}
appsDropdown={<AppsDropdown />}
>
<SidebarNav>
<SidebarList>
<SidebarListItem>
<a href="/inbox">Inbox</a>
</SidebarListItem>
<SidebarListItem>
<a href="/sent">Sent</a>
</SidebarListItem>
</SidebarList>
</SidebarNav>
</Sidebar>
);
};
Props
Extends ComponentPropsWithoutRef<'div'>
Application identifier (e.g., APPS.PROTONMAIL)
Logo component to display
Whether sidebar is expanded (mobile only). Default: false
Callback when sidebar expand/collapse is toggled
Primary action button (e.g., “Compose” button)
Sidebar navigation content
Version information to display
Whether to show app links. Default: true
Content rendered before storage meter
Content rendered after storage meter
Whether content grows to fill available space. Default: true
Whether to show storage meter. Default: true
Whether sidebar is collapsed. Default: false
Ref for navigation container
Use wavy style for storage meter. Default: false
Used on Mail Desktop App for draggable areas. Default: false
Examples
Navigation container.
import SidebarNav from '@proton/components/components/sidebar/SidebarNav';
<SidebarNav>
<SidebarList>{/* Items */}</SidebarList>
</SidebarNav>
List container for sidebar items.
import SidebarList from '@proton/components/components/sidebar/SidebarList';
<SidebarList>
{/* List items */}
</SidebarList>
Individual sidebar list item.
import SidebarListItem from '@proton/components/components/sidebar/SidebarListItem';
<SidebarListItem>
<a href="/inbox">Inbox</a>
</SidebarListItem>
Sidebar link with icon support.
import SidebarListItemLink from '@proton/components/components/sidebar/SidebarListItemLink';
<SidebarListItemLink to="/inbox" icon="inbox">
Inbox
</SidebarListItemLink>
Clickable sidebar item.
import SidebarListItemButton from '@proton/components/components/sidebar/SidebarListItemButton';
<SidebarListItemButton onClick={handleClick}>
Action
</SidebarListItemButton>
Primary action button for sidebar.
import SidebarPrimaryButton from '@proton/components/components/sidebar/SidebarPrimaryButton';
<SidebarPrimaryButton onClick={handleCompose}>
Compose
</SidebarPrimaryButton>
Logo component for sidebar header.
import SidebarLogo from '@proton/components/components/sidebar/SidebarLogo';
<SidebarLogo app={APPS.PROTONMAIL} />
Storage Meter
The sidebar automatically displays a storage meter showing used/available space. This can be controlled with the showStorage prop.
<Sidebar
app={APPS.PROTONMAIL}
showStorage={true}
wavyMeter={false}
// ... other props
>
{/* Content */}
</Sidebar>
Best Practices
Mobile Responsiveness
const [expanded, setExpanded] = useState(false);
return (
<>
{/* Mobile hamburger button */}
<Button
className="md:hidden"
onClick={() => setExpanded(true)}
>
<Icon name="hamburger" />
</Button>
<Sidebar
app={APPS.PROTONMAIL}
expanded={expanded}
onToggleExpand={() => setExpanded(false)}
// ... other props
>
{/* Navigation */}
</Sidebar>
</>
);
const [collapsed, setCollapsed] = useState(false);
return (
<div className="flex">
<Sidebar
app={APPS.PROTONMAIL}
collapsed={collapsed}
logo={collapsed ? <IconLogo /> : <FullLogo />}
primary={
collapsed ? (
<Button icon onClick={handleCompose}>
<Icon name="pen" />
</Button>
) : (
<Button fullWidth onClick={handleCompose}>
Compose
</Button>
)
}
>
<SidebarNav>
<SidebarList>
<SidebarListItemLink to="/inbox" icon="inbox">
{!collapsed && 'Inbox'}
</SidebarListItemLink>
</SidebarList>
</SidebarNav>
</Sidebar>
<Button
className="sidebar-toggle"
onClick={() => setCollapsed(!collapsed)}
>
<Icon name={collapsed ? 'chevron-right' : 'chevron-left'} />
</Button>
</div>
);
Navigation Structure
<Sidebar app={APPS.PROTONMAIL} /* ... */>
<SidebarNav>
{/* Main navigation */}
<SidebarList>
<SidebarListItemLink to="/inbox" icon="inbox">
Inbox <span className="ml-auto">5</span>
</SidebarListItemLink>
<SidebarListItemLink to="/sent" icon="paper-plane">
Sent
</SidebarListItemLink>
</SidebarList>
{/* Folders section */}
<SidebarList>
<h3 className="text-sm color-weak px-4">Folders</h3>
<SidebarListItemLink to="/folder/work" icon="folder">
Work
</SidebarListItemLink>
<SidebarListItemLink to="/folder/personal" icon="folder">
Personal
</SidebarListItemLink>
</SidebarList>
{/* Labels section */}
<SidebarList>
<h3 className="text-sm color-weak px-4">Labels</h3>
<SidebarListItemLink to="/label/important">
<span className="color-danger">•</span> Important
</SidebarListItemLink>
</SidebarList>
</SidebarNav>
</Sidebar>
Accessibility
<Sidebar
app={APPS.PROTONMAIL}
role="navigation"
aria-label="Main navigation"
/* ... */
>
<SidebarNav>
<SidebarList role="list">
<SidebarListItemLink
to="/inbox"
aria-current={currentPath === '/inbox' ? 'page' : undefined}
>
Inbox
</SidebarListItemLink>
</SidebarList>
</SidebarNav>
</Sidebar>
Layout Integration
const AppLayout = () => {
return (
<div className="flex h-full">
<Sidebar
app={APPS.PROTONMAIL}
logo={<Logo />}
appsDropdown={<AppsDropdown />}
primary={
<Button fullWidth color="norm">
Compose
</Button>
}
>
<SidebarNav>
{/* Navigation items */}
</SidebarNav>
</Sidebar>
<main className="flex-1 flex flex-column">
<Header>{/* Header content */}</Header>
<div className="flex-1 overflow-auto">
{/* Main content */}
</div>
</main>
</div>
);
};
Source Code
View source:
- Sidebar:
packages/components/components/sidebar/Sidebar.tsx:1
- SidebarNav:
packages/components/components/sidebar/SidebarNav.tsx:1
- SidebarListItem:
packages/components/components/sidebar/SidebarListItem.tsx:1