A SideNavPanel contains a SideNav and other app chrome in a container that collapses to an icon rail.
A SideNavPanel wraps a SideNav, along with any other app chrome, in a container that collapses down to a narrow icon rail. It renders its own collapse/expand toggle at the bottom of the panel, and animates its width between the two states.
The expanded width comes from the styles prop you pass to SideNavPanel.
import {SideNavPanel, SideNav, SideNavItem, SideNavItemContent, SideNavItemLink, SideNavSection, SideNavHeader, Text} from '@react-spectrum/s2/SideNavPanel';
import {SideNavPanelApp} from './SideNavPanelApp';
import {style} from '@react-spectrum/s2/style' with {type: 'macro'};
import CCLibrary from '@react-spectrum/s2/icons/CCLibrary';
import Files from '@react-spectrum/s2/icons/Files';
import Images from '@react-spectrum/s2/icons/Images';
import Project from '@react-spectrum/s2/icons/Project';
<SideNavPanelApp defaultSelectedRoute="/files">
{({selectedRoute}) => (
<SideNavPanel
defaultCollapsed
styles={style({gridArea: 'sidebar', width: 208, marginX: 8})}>
<SideNav
aria-label="Files"
selectedRoute={selectedRoute}
defaultExpandedKeys={['projects']}
styles={style({width: 'full'})}>
<SideNavItem href="/files" textValue="Files">
<SideNavItemContent>
<SideNavItemLink>
<Files />
<Text>Files</Text>
</SideNavItemLink>
</SideNavItemContent>
</SideNavItem>
<SideNavItem id="your-libraries" href="/your-libraries" textValue="Your Libraries">
<SideNavItemContent>
<SideNavItemLink>
<CCLibrary />
<Text>Your Libraries</Text>
</SideNavItemLink>
</SideNavItemContent>
<SideNavItem href="/photos" textValue="Photos">
<SideNavItemContent>
<SideNavItemLink>
<Images />
<Text>Photos</Text>
</SideNavItemLink>
</SideNavItemContent>
</SideNavItem>
</SideNavItem>
<SideNavSection>
<SideNavHeader>Work</SideNavHeader>
<SideNavItem id="projects" href="/projects" textValue="Projects">
<SideNavItemContent>
<SideNavItemLink>
<Project />
<Text>Projects</Text>
</SideNavItemLink>
</SideNavItemContent>
<SideNavItem href="/projects/website" textValue="Website redesign">
<SideNavItemContent>
<SideNavItemLink>
<Text>Website redesign</Text>
</SideNavItemLink>
</SideNavItemContent>
</SideNavItem>
<SideNavItem href="/projects/mobile" textValue="Mobile app">
<SideNavItemContent>
<SideNavItemLink>
<Text>Mobile app</Text>
</SideNavItemLink>
</SideNavItemContent>
</SideNavItem>
</SideNavItem>
</SideNavSection>
</SideNav>
</SideNavPanel>
)}
</SideNavPanelApp>
Collapsing
The collapsed state is uncontrolled by default. Use defaultCollapsed for the initial state, or isCollapsed together with onCollapsedChange to control it — for example to persist the user's preference, or to collapse the panel from elsewhere in the app.
import {SideNavPanel, SideNav, SideNavItem, SideNavItemContent, SideNavItemLink, Collection, Text} from '@react-spectrum/s2/SideNavPanel';
import {SideNavPanelApp} from './SideNavPanelApp';
import {style} from '@react-spectrum/s2/style' with {type: 'macro'};
import File from '@react-spectrum/s2/icons/File';
import Files from '@react-spectrum/s2/icons/Files';
import Folder from '@react-spectrum/s2/icons/Folder';
import Images from '@react-spectrum/s2/icons/Images';
import {useState} from 'react';
function CollapsibleSideNavPanel() {
let [isCollapsed, setCollapsed] = useState(true);
return (
<SideNavPanelApp
defaultSelectedRoute="/notes"
isCollapsed={isCollapsed}
onCollapsedChange={setCollapsed}>
{({selectedRoute}) => (
<SideNavPanel
isCollapsed={isCollapsed}
onCollapsedChange={setCollapsed}
styles={style({gridArea: 'sidebar', width: 208, marginX: 8})}>
<SideNav
aria-label="Files"
selectedRoute={selectedRoute}
items={items}
styles={style({width: 'full'})}>
{function renderItem(item) {
let Icon = item.icon ?? (item.type === 'directory' ? Folder : File);
return (
<SideNavItem textValue={item.title} href={item.href}>
<SideNavItemContent>
<SideNavItemLink>
<Icon />
<Text>{item.title}</Text>
</SideNavItemLink>
</SideNavItemContent>
{item.children && <Collection items={item.children}>
{renderItem}
</Collection>}
</SideNavItem>
);
}}
</SideNav>
</SideNavPanel>
)}
</SideNavPanelApp>
);
}
<CollapsibleSideNavPanel />
Animations
SideNavPanel and SideNav animate themselves. The panel's width animates first, and its contents animate only once it has settled.
Because the contents wait for the width, the isCollapsed you read from SideNavPanelContext trails the panel itself while it is expanding.
AccountFooter in the example below reads isCollapsed from SideNavPanelContext and hides its name with display: none while the panel is collapsed.
| Context value | Description |
|---|---|
isCollapsed | Whether the panel's contents are collapsed. This trails the panel itself while it is expanding, since its contents are only brought back once it has finished widening. |
setCollapsed | Collapses or expands the panel. Useful for building your own expand and collapse trigger. |
import {SideNavPanel, SideNav, SideNavItem, SideNavItemContent, SideNavItemLink, Collection, Text} from '@react-spectrum/s2/SideNavPanel';
import {SideNavPanelApp, AccountFooter} from './SideNavPanelApp';
import {style} from '@react-spectrum/s2/style' with {type: 'macro'};
import File from '@react-spectrum/s2/icons/File';
import Files from '@react-spectrum/s2/icons/Files';
import Images from '@react-spectrum/s2/icons/Images';
import Archive from '@react-spectrum/s2/icons/Archive';
import Folder from '@react-spectrum/s2/icons/Folder';
<SideNavPanelApp defaultSelectedRoute="/notes">
{({selectedRoute}) => (
<SideNavPanel defaultCollapsed styles={style({gridArea: 'sidebar', width: 208, marginX: 8})}>
<SideNav
aria-label="Files"
selectedRoute={selectedRoute}
items={items}
styles={style({width: 'full'})}>
{function renderItem(item) {
let Icon = item.icon ?? (item.type === 'directory' ? Folder : File);
return (
<SideNavItem textValue={item.title} href={item.href}>
<SideNavItemContent>
<SideNavItemLink>
<Icon />
<Text>{item.title}</Text>
</SideNavItemLink>
</SideNavItemContent>
{item.children && <Collection items={item.children}>
{renderItem}
</Collection>}
</SideNavItem>
);
}}
</SideNav>
<AccountFooter />
</SideNavPanel>
)}
</SideNavPanelApp>
API
<SideNavPanel>
<SideNav>
<SideNavItem href>
<SideNavItemContent>
<SideNavItemLink>
<Icon />
<Text />
</SideNavItemLink>
</SideNavItemContent>
</SideNavItem>
</SideNav>
</SideNavPanel>
SideNavPanel Props
| Name | Type | |
|---|---|---|
children | ReactNode | |
The content of the side panel. | ||
isCollapsed | boolean | |
Whether the side panel is collapsed (controlled). | ||
defaultCollapsed | boolean | |
Whether the side panel is collapsed by default (uncontrolled). | ||
styles | StylesPropWithHeight | |
Spectrum-defined styles, returned by the | ||
