SideNavigation
Props
Usage guidelines
- When Tabs or a top navigation cannot accommodate the number of links or sections you need to navigate through
- When a deep hierarchy of navigation items is needed
Best practices
Keep item labels brief and clear to keep them memorable and scannable.
Use long text labels that end up wrapping, especially in certain languages. Don’t shorten labels so much that they are hard to understand.
Group related items and use section headings to help users parse information and help with redundancy.
Provide an unordered “kitchen sink” of features that is hard to parse and creates redundancy.
Use icons that clearly match their text labels and serve as bullet points for the content.
Use icons if you’ll be forced to include icons that don’t quite reinforce their text labels.
Place under the PageHeader when SideNav is used to navigate urls that are sub-sections of a main page
Omit a PageHeader and make it seem like each SideNav item is a primary, independent page.
Accessibility
Active item
SideNavigation.TopItem and SideNavigation.NestedItem have an "active" state that visually identifies it. To set them to "active" set 'active="page"' (page redirect) or 'active="section"'. Use routing hooks from React.Router or other frameworks to identify the current route. For example, if the current pathname matches the SideNavigation.TopItem href, set SideNavigation.TopItem to "page". Use the example below as a reference.
import React from 'react'; import { SideNavigation } from 'gestalt'; export default function Example() { const reactRouterPath = '/sidenavigation'; return ( <SideNavigation accessibilityLabel="Active item example"> <SideNavigation.Section label="Navigation"> <SideNavigation.TopItem href="#" label="PageHeader" /> <SideNavigation.TopItem href="#" label="Tabs" /> <SideNavigation.TopItem active={reactRouterPath === '/sidenavigation' ? 'page' : undefined} badge={{ text: 'New', type: 'info' }} href="#" label="SideNavigation" /> </SideNavigation.Section> <SideNavigation.Section label="Controls"> <SideNavigation.TopItem badge={{ text: 'Deprecated', type: 'warning' }} href="#" label="RadioButton" /> <SideNavigation.TopItem href="#" label="RadioGroup" /> </SideNavigation.Section> </SideNavigation> ); }
Localization
Be sure to localize all text strings. Note that localization can lengthen text by 20 to 30 percent.
When the text of the SideNav.Item becomes longer than the width of the menu, either intentionally or through localization, will wrap as needed to display the full text. Keep this in mind when selecting wording for your SideNavigation menu items.
Note that dismissButton.accessibilityLabel
is optional as DefaultLabelProvider provides default strings. Use custom labels if they need to be more specific.
import React from 'react'; import { DefaultLabelProvider, SideNavigation } from 'gestalt'; export default function Example() { return ( <DefaultLabelProvider labels={{ SideNavigation: { accessibilityDismissButtonLabel: 'Seitennavigation verwerfen', }, }} > <SideNavigation accessibilityLabel="Beispiel für Lokalisierung"> <SideNavigation.TopItem counter={{ number: '20', accessibilityLabel: 'Sie haben 20 Benachrichtigungen', }} href="#" icon="bell" label="Benachrichtigungen" notificationAccessibilityLabel="Du hast neue Benachrichtigungen" onClick={({ event }) => event.preventDefault()} /> <SideNavigation.TopItem counter={{ number: '10', accessibilityLabel: 'Sie haben 10 Nachrichten', }} href="#" icon="speech" label="Mitteilungen" notificationAccessibilityLabel="Sie haben neue Nachrichten" onClick={({ event }) => event.preventDefault()} /> <SideNavigation.TopItem href="#" icon="cog" label="Einstellungen" onClick={({ event }) => event.preventDefault()} /> <SideNavigation.TopItem href="#" icon="lock" label="Geschäftszugriff" onClick={({ event }) => event.preventDefault()} /> <SideNavigation.TopItem badge={{ text: 'Neu', type: 'info' }} href="#" icon="add-layout" label="Optimieren Sie Ihren Home-Feed" onClick={({ event }) => event.preventDefault()} /> </SideNavigation> </DefaultLabelProvider> ); }
Subcomponents
Use SideNavigation.Section to categorize navigation menu items into groups and also avoid redundant language in labels.
Use SideNavigation.TopItem to redirect the user to a different page or section. SideNavigation.TopItem must be used at the top level of SideNavigation. It supports badges, icons, counters, and notifications.
Use SideNavigation.NestedItem to redirect the user to a different page or section. SideNavigation.NestedItem must be used in second and third nested levels.
Use SideNavigation.Group to hold SideNavigation.NestedItem and SideNavigation.NestedGroup at the top level of SideNavigation. It supports badges, icons, counters, and notifications.
Use SideNavigation.NestedGroup to hold SideNavigation.NestedItem in the second nested level of Pageheader.
Variants
Sections
Sections help with categorizing navigation menu items into groups and also avoid redundant language in labels.
import React from 'react'; import { SideNavigation } from 'gestalt'; export default function Example() { return ( <SideNavigation accessibilityLabel="Sections example"> <SideNavigation.Section label="Resources"> <SideNavigation.TopItem href="#" label="ESLint plugin" /> <SideNavigation.TopItem href="#" label="FAQ" /> <SideNavigation.TopItem href="#" label="How to hack around Gestalt" /> <SideNavigation.TopItem href="#" label="Tooling" /> </SideNavigation.Section> <SideNavigation.Section label="Foundations"> <SideNavigation.TopItem href="#" label="Accessibility" /> <SideNavigation.TopItem href="#" label="Elevation" /> <SideNavigation.TopItem href="#" label="Typography" /> <SideNavigation.TopItem href="#" label="Color palette" /> </SideNavigation.Section> </SideNavigation> ); }
Header
Headers allow for sorting filters or another UI control to be included at the top of the navigation.
import { Fragment, useState } from 'react'; import { Flex, RadioGroup, SideNavigation } from 'gestalt'; export default function Example() { const [organisedBy, setOrganisedBy] = useState('categorized'); return ( <SideNavigation accessibilityLabel="Header example" header={ <RadioGroup id="example-header" legend="Sort by?"> <Flex gap={{ row: 2, column: 0, }} > <RadioGroup.RadioButton checked={organisedBy === 'categorized'} id="category" label="Category" name="SortCategory" onChange={() => setOrganisedBy('categorized')} size="sm" value="categorized" /> <RadioGroup.RadioButton checked={organisedBy === 'alphabetical'} id="alphabetical" label="Alphabetical" name="SortCAlphabetical" onChange={() => setOrganisedBy('alphabetical')} size="sm" value="alphabetical" /> </Flex> </RadioGroup> } > {organisedBy === 'categorized' ? ( <Fragment> <SideNavigation.Section label="Navigation"> <SideNavigation.TopItem href="#" label="PageHeader" /> <SideNavigation.TopItem href="#" label="Tabs" /> <SideNavigation.TopItem badge={{ text: 'New', type: 'info' }} href="#" label="SideNavigation" /> </SideNavigation.Section> <SideNavigation.Section label="Controls"> <SideNavigation.TopItem badge={{ text: 'Deprecated', type: 'warning' }} href="#" label="RadioButton" /> <SideNavigation.TopItem href="#" label="RadioGroup" /> </SideNavigation.Section> </Fragment> ) : ( <Fragment> <SideNavigation.TopItem href="#" label="PageHeader" /> <SideNavigation.TopItem badge={{ text: 'Deprecated', type: 'warning' }} href="#" label="RadioButton" /> <SideNavigation.TopItem href="#" label="RadioGroup" /> <SideNavigation.TopItem badge={{ text: 'New', type: 'info' }} href="#" label="SideNavigation" /> <SideNavigation.TopItem href="/web/tabs" label="Tabs" /> </Fragment> )} </SideNavigation> ); }
Footers allow for filters, additional external links or other UI controls to be included at the bottom of the navigation.
import { Box, Fieldset, Flex, SideNavigation, Text } from 'gestalt'; import { DatePicker } from 'gestalt-datepicker'; export default function Example() { return ( <Box height="100%" padding={2} width={300}> <SideNavigation accessibilityLabel="Footer example" footer={ <Flex direction="column" gap={{ column: 4, row: 0 }}> <Text size="300" weight="bold"> Filters </Text> <Fieldset legend="Campaign filters" legendDisplay="hidden"> <Flex direction="column" gap={{ column: 4, row: 0 }}> <DatePicker id="example-start-date" label="Start" onChange={() => {}} rangeSelector="start" value={new Date()} /> <DatePicker id="example-end-date" label="End" onChange={() => {}} rangeSelector="end" value={new Date(+7)} /> </Flex> </Fieldset> </Flex> } > <SideNavigation.Section label="Campaigns"> {[ { label: 'Active', counter: { number: '200', accessibilityLabel: '200 Pins' }, }, { label: 'Draft', counter: { number: '100', accessibilityLabel: '100 Pins' }, }, ].map(({ label, counter }) => ( <SideNavigation.TopItem key={label} counter={counter} href="#" icon="ads-stats" label={label} /> ))} </SideNavigation.Section> </SideNavigation> </Box> ); }
Badge
A badge can be added to a menu label with information that may be useful to a person, such as whether a page is new or is a beta or deprecated feature. Only supported in SideNavigation.TopItem and SideNavigation.Group.
import React from 'react'; import { SideNavigation } from 'gestalt'; export default function Example() { return ( <SideNavigation accessibilityLabel="Badge example"> <SideNavigation.Section label="Navigation"> <SideNavigation.TopItem href="#" label="PageHeader" /> <SideNavigation.TopItem href="#" label="Tabs" /> <SideNavigation.TopItem badge={{ text: 'New', type: 'info' }} href="#" label="SideNavigation" /> </SideNavigation.Section> <SideNavigation.Section label="Controls"> <SideNavigation.TopItem badge={{ text: 'Deprecated', type: 'warning' }} href="#" label="RadioButton" /> <SideNavigation.TopItem href="#" label="RadioGroup" /> </SideNavigation.Section> </SideNavigation> ); }
Border
A border can be added to the end edge of the navigation on dense surfaces with tight spacing where it helps to visually separate the nav from other content.
import React from 'react'; import { SideNavigation } from 'gestalt'; export default function Example() { return ( <SideNavigation accessibilityLabel="Border example" showBorder> <SideNavigation.Section label="Navigation"> <SideNavigation.TopItem href="#" label="PageHeader" /> <SideNavigation.TopItem href="#" label="Tabs" /> <SideNavigation.TopItem href="#" label="SideNavigation" /> </SideNavigation.Section> <SideNavigation.Section label="Controls"> <SideNavigation.TopItem href="#" label="RadioButton" /> <SideNavigation.TopItem href="#" label="RadioGroup" /> </SideNavigation.Section> </SideNavigation> ); }
Disabled
Items can be disabled to prevent clicking or navigation to a page if that page is unavailable to users.
import React from 'react'; import { Box, SideNavigation } from 'gestalt'; export default function Example() { return ( <Box height="100%" width={300}> <SideNavigation accessibilityLabel="Disabled item example"> <SideNavigation.TopItem disabled href="#" icon="ads-stats" label="Reports" onClick={({ event }) => event.preventDefault()} /> <SideNavigation.Section label="Catalogs"> <SideNavigation.TopItem disabled href="#" icon="people" label="Thanksgiving" onClick={({ event }) => event.preventDefault()} subtext="Disabled thanksgiving section" /> <SideNavigation.Group expanded icon="people" label="Christmas"> <SideNavigation.NestedItem disabled href="#" label="Luxury Christmas" onClick={({ event }) => event.preventDefault()} /> <SideNavigation.NestedGroup label="Shopping Categories"> <SideNavigation.NestedItem disabled href="#" label="Gifts" onClick={({ event }) => event.preventDefault()} /> <SideNavigation.NestedItem href="#" label="Decorations" onClick={({ event }) => event.preventDefault()} /> </SideNavigation.NestedGroup> </SideNavigation.Group> </SideNavigation.Section> </SideNavigation> </Box> ); }
Subtext
Subtext adds a new line to an item, providing additional information about the page the item represents.
import React from 'react'; import { Box, SideNavigation } from 'gestalt'; export default function Example() { return ( <Box height="100%" width={300}> <SideNavigation accessibilityLabel="Helper text items"> <SideNavigation.TopItem href="#" icon="ads-stats" label="Reports" onClick={({ event }) => event.preventDefault()} subtext="Reporting subtext" /> <SideNavigation.Section label="Audiences"> <SideNavigation.TopItem href="#" icon="people" label="Group A" onClick={({ event }) => event.preventDefault()} subtext="8.5m+ users" /> <SideNavigation.Group expanded icon="people" label="Group B"> <SideNavigation.NestedItem href="#" label="Sub audience 1" onClick={({ event }) => event.preventDefault()} subtext="2.3m+ users" /> <SideNavigation.NestedGroup label="Sub audience 2"> <SideNavigation.NestedItem href="#" label="Region 1" onClick={({ event }) => event.preventDefault()} subtext="100k+ users" /> <SideNavigation.NestedItem href="#" label="Region 2" onClick={({ event }) => event.preventDefault()} subtext="50k+ users" /> </SideNavigation.NestedGroup> </SideNavigation.Group> </SideNavigation.Section> </SideNavigation> </Box> ); }
Icons
Icons are used when simple, clear icons help users with scanning the content of a menu. Only supported in SideNavigation.TopItem and SideNavigation.Group.
import React from 'react'; import { SideNavigation } from 'gestalt'; export default function Example() { return ( <SideNavigation accessibilityLabel="Icons example"> <SideNavigation.TopItem href="#" icon="bell" label="Notifications" onClick={({ event }) => event.preventDefault()} /> <SideNavigation.TopItem href="#" icon="speech" label="Messages" onClick={({ event }) => event.preventDefault()} /> <SideNavigation.TopItem href="#" icon="cog" label="Settings" onClick={({ event }) => event.preventDefault()} /> <SideNavigation.TopItem href="#" icon="lock" label="Business Access" onClick={({ event }) => event.preventDefault()} /> <SideNavigation.TopItem href="#" icon="add-layout" label="Tune your home feed" onClick={({ event }) => event.preventDefault()} /> </SideNavigation> ); }
import React from 'react'; import { SideNavigation } from 'gestalt'; export default function Example() { return ( <SideNavigation accessibilityLabel="Custom icons example"> <SideNavigation.TopItem href="#" icon={{ __path: 'M14 17.5c0 1.378-1.122 2.5-2.5 2.5A2.503 2.503 0 0 1 9 17.5V17h5v.5zm8.947-1.87L18.701 2.712a1.022 1.022 0 0 0-1.566-.521l-15.7 11.24c-.37.264-.525.744-.382 1.179l.551 1.678c.14.425.532.712.974.712H7v.5a4.5 4.5 0 0 0 9 0V17h5.973c.7 0 1.195-.696.974-1.37z', }} label="Notifications" onClick={({ event }) => event.preventDefault()} /> <SideNavigation.TopItem href="#" icon={{ __path: 'M0 6a4 4 0 0 1 4-4h16a4 4 0 0 1 4 4v12a4 4 0 0 1-4 4H4a4 4 0 0 1-4-4zm3.52-.88 7.53 6.16a1.5 1.5 0 0 0 1.9 0l7.53-6.16A1 1 0 0 0 20 5H4a1 1 0 0 0-.48.12zM3 8.57V18a1 1 0 0 0 1 1h16a1 1 0 0 0 1-1V8.57l-6.15 5.04a4.5 4.5 0 0 1-5.7 0z', }} label="Messages" onClick={({ event }) => event.preventDefault()} /> <SideNavigation.TopItem href="#" icon={{ __path: 'm2.337 19.942 5.671-1.977L19.265 6.706c.981-.98.981-2.57 0-3.55l-1.42-1.421a2.51 2.51 0 0 0-3.55 0L3.036 12.992l-1.978 5.671a1.005 1.005 0 0 0 1.279 1.279M23 22c0 .55-.45 1-1 1H2c-.55 0-1-.45-1-1s.45-1 1-1h20c.55 0 1 .45 1 1', }} label="Settings" onClick={({ event }) => event.preventDefault()} /> <SideNavigation.TopItem href="#" icon={{ __path: 'M23 5v14a4 4 0 0 1-4 4H5a4 4 0 0 1-4-4v-5.5h10.258l-1.94 1.939a1.5 1.5 0 0 0 2.121 2.122L17 12l-5.561-5.561a1.501 1.501 0 0 0-2.121 2.122l1.94 1.939H1V5a4 4 0 0 1 4-4h14a4 4 0 0 1 4 4', }} label="Business Access" onClick={({ event }) => event.preventDefault()} /> <SideNavigation.TopItem href="#" icon={{ __path: 'M5 1h5.75v22H5c-2.2 0-4-1.8-4-4V5c0-2.2 1.8-4 4-4zm18 4v5.75h-9.75V1H19c2.2 0 4 1.8 4 4zm-9.75 8.25H23V19c0 2.2-1.8 4-4 4h-5.75z', }} label="Tune your home feed" onClick={({ event }) => event.preventDefault()} /> </SideNavigation> ); }
Notification
A red indicator dot can be added to signify new items on a page or things that need your attention. Only supported in SideNavigation.TopItem and SideNavigation.Group.
import React from 'react'; import { SideNavigation } from 'gestalt'; export default function Example() { return ( <SideNavigation accessibilityLabel="Notification example"> <SideNavigation.TopItem counter={{ number: '20', accessibilityLabel: 'You have 20 notifications in your inbox', }} href="#" label="Notifications" notificationAccessibilityLabel="New notifications" onClick={({ event }) => event.preventDefault()} /> <SideNavigation.TopItem counter={{ number: '10', accessibilityLabel: 'You have 10 messages in your inbox', }} href="#" label="Messages" notificationAccessibilityLabel="New messages" onClick={({ event }) => event.preventDefault()} /> <SideNavigation.TopItem href="#" label="Settings" onClick={({ event }) => event.preventDefault()} /> <SideNavigation.TopItem href="#" label="Business Access" onClick={({ event }) => event.preventDefault()} /> <SideNavigation.TopItem href="#" label="Tune your home feed" onClick={({ event }) => event.preventDefault()} /> </SideNavigation> ); }
Counters
Counters can be included as indicators of the number of items on a page or section. Only include counters if the information is useful for the user to know before clicking on a menu item. To prevent visual overload, do not include counters in the parent if the children have counters.
import React from 'react'; import { SideNavigation } from 'gestalt'; export default function Example() { return ( <SideNavigation accessibilityLabel="Counters example"> <SideNavigation.Section label="Ads"> <SideNavigation.TopItem counter={{ number: '2', accessibilityLabel: 'You have 2 campaigns' }} href="#" label="Campaigns" onClick={({ event }) => event.preventDefault()} /> <SideNavigation.Group label="Catalogues"> <SideNavigation.NestedGroup label="Christmas"> <SideNavigation.NestedItem counter={{ number: '20', accessibilityLabel: 'You have 20 data sources', }} href="#" label="Data sources" onClick={({ event }) => event.preventDefault()} /> <SideNavigation.NestedItem counter={{ number: '5', accessibilityLabel: 'You have 5 product groups', }} href="#" label="Product groups" onClick={({ event }) => event.preventDefault()} /> <SideNavigation.NestedItem counter={{ number: '200', accessibilityLabel: 'You have 200 listings', }} href="#" label="Listings" onClick={({ event }) => event.preventDefault()} /> </SideNavigation.NestedGroup> <SideNavigation.NestedGroup label="Thanksgiving"> <SideNavigation.NestedItem counter={{ number: '15', accessibilityLabel: 'You have 15 data sources', }} href="#" label="Data sources" onClick={({ event }) => event.preventDefault()} /> <SideNavigation.NestedItem counter={{ number: '3', accessibilityLabel: 'You have 3 product groups', }} href="#" label="Product groups" onClick={({ event }) => event.preventDefault()} /> <SideNavigation.NestedItem counter={{ number: '100', accessibilityLabel: 'You have 100 listings', }} href="#" label="Listings" onClick={({ event }) => event.preventDefault()} /> </SideNavigation.NestedGroup> </SideNavigation.Group> </SideNavigation.Section> </SideNavigation> ); }
Primary action
SideNavigation.TopItem and SideNavigation.Group support an optional primaryAction
.
primaryAction
can be a simple
IconButton or a
Dropdown. For the latter, set dropdownItems
using an array of
Dropdown.Item.
import { useState } from 'react'; import { Box, Button, DeviceTypeProvider, Dropdown, Flex, SideNavigation, } from 'gestalt'; export default function Example() { const [mobile, setMobile] = useState(false); return ( <Box color="lightWash" height="100%" padding={4} position="relative"> <Flex gap={12} justifyContent="center" wrap> <Button color="red" onClick={() => setMobile(true)} text="View mobile" /> <DeviceTypeProvider deviceType={mobile ? 'mobile' : 'desktop'}> <Box bottom id="sidenavigation" left={mobile} position={mobile ? 'absolute' : undefined} right={mobile} top={mobile} width={mobile ? '100%' : 360} > <SideNavigation accessibilityLabel="Notification example" dismissButton={{ onDismiss: () => setMobile((value) => !value) }} > <SideNavigation.TopItem counter={{ number: '10', accessibilityLabel: '10 updates' }} href="#" label="Campaign z-168i" onClick={({ event }) => { event.preventDefault(); }} primaryAction={{ icon: 'edit', onClick: ({ event }) => { event.preventDefault(); }, tooltip: { text: 'Rename campaign' }, }} /> <SideNavigation.TopItem href="#" label="Campaign a-j6ki (inactive)" onClick={({ event }) => { event.preventDefault(); }} primaryAction={{ icon: 'trash-can', onClick: ({ event }) => { event.preventDefault(); }, tooltip: { text: 'Delete campaign' }, }} /> <SideNavigation.Group counter={{ number: '12', accessibilityLabel: '12 campaign drafts', }} label="Campaign drafts" primaryAction={{ onClick: ({ event }) => { event.preventDefault(); }, tooltip: { text: 'More options' }, dropdownItems: [ <Dropdown.Item key="edit" onSelect={() => {}} option={{ value: 'Edit', label: 'Edit' }} />, <Dropdown.Item key="trash" onSelect={() => {}} option={{ value: 'Delete', label: 'Delete' }} />, ], }} > <SideNavigation.NestedItem counter={{ number: '10', accessibilityLabel: 'You have 10 messages in your inbox', }} href="#" label="West Coast" onClick={({ event }) => event.preventDefault()} primaryAction={{ onClick: ({ event }) => { event.preventDefault(); }, tooltip: { text: 'More options' }, dropdownItems: [ <Dropdown.Item key="edit" onSelect={() => {}} option={{ value: 'Edit', label: 'Edit' }} />, <Dropdown.Item key="trash" onSelect={() => {}} option={{ value: 'Delete', label: 'Delete' }} />, ], }} /> <SideNavigation.NestedItem href="#" label="East Coast" onClick={({ event }) => event.preventDefault()} primaryAction={{ onClick: ({ event }) => { event.preventDefault(); }, tooltip: { text: 'More options' }, dropdownItems: [ <Dropdown.Item key="edit" onSelect={() => {}} option={{ value: 'Edit', label: 'Edit' }} />, <Dropdown.Item key="trash" onSelect={() => {}} option={{ value: 'Delete', label: 'Delete' }} />, ], }} /> <SideNavigation.NestedGroup label="Alternative campaigns" primaryAction={{ onClick: ({ event }) => { event.preventDefault(); }, tooltip: { text: 'More options' }, dropdownItems: [ <Dropdown.Item key="edit" onSelect={() => {}} option={{ value: 'Edit', label: 'Edit' }} />, <Dropdown.Item key="trash" onSelect={() => {}} option={{ value: 'Delete', label: 'Delete' }} />, ], }} > <SideNavigation.NestedItem href="#" label="West Coast" onClick={({ event }) => event.preventDefault()} primaryAction={{ onClick: ({ event }) => { event.preventDefault(); }, tooltip: { text: 'More options' }, dropdownItems: [ <Dropdown.Item key="edit" onSelect={() => {}} option={{ value: 'Edit', label: 'Edit' }} />, <Dropdown.Item key="trash" onSelect={() => {}} option={{ value: 'Delete', label: 'Delete' }} />, ], }} /> <SideNavigation.NestedItem href="#" label="East Coast" onClick={({ event }) => event.preventDefault()} /> </SideNavigation.NestedGroup> </SideNavigation.Group> <SideNavigation.TopItem counter={{ number: '87', accessibilityLabel: '87 archived campaings', }} href="#" label="Archived campaigns" onClick={({ event }) => event.preventDefault()} primaryAction={{ onClick: ({ event }) => { event.preventDefault(); }, tooltip: { text: 'More options' }, dropdownItems: [ <Dropdown.Item key="edit" onSelect={() => {}} option={{ value: 'Edit', label: 'Edit' }} />, <Dropdown.Item key="trash" onSelect={() => {}} option={{ value: 'Delete', label: 'Delete' }} />, ], }} /> </SideNavigation> </Box> </DeviceTypeProvider> </Flex> </Box> ); }
Nested directory
SideNavigation supports three navigation levels. The top level is composed of SideNavigation.TopItem and SideNavigation.Group. The second nested level is composed of SideNavigation.NestedGroup and SideNavigation.Item. The third nested level is composed of SideNavigation.Item
import React from 'react'; import { Box, SideNavigation } from 'gestalt'; export default function Example() { return ( <Box height="100%" width={300}> <SideNavigation accessibilityLabel="Nested items example"> <SideNavigation.TopItem href="#" icon="ads-stats" label="Reporting" onClick={({ event }) => event.preventDefault()} /> <SideNavigation.TopItem href="#" icon="replace" label="Conversions" onClick={({ event }) => event.preventDefault()} /> <SideNavigation.Section label="Audiences"> <SideNavigation.TopItem href="#" icon="people" label="Thanksgiving" onClick={({ event }) => event.preventDefault()} /> <SideNavigation.Group icon="people" label="Christmas"> <SideNavigation.NestedItem href="#" label="Luxury Christmas" onClick={({ event }) => event.preventDefault()} /> <SideNavigation.NestedGroup label="Classic Christmas"> <SideNavigation.NestedItem href="#" label="West Coast" onClick={({ event }) => event.preventDefault()} /> <SideNavigation.NestedItem href="#" label="East Coast" onClick={({ event }) => event.preventDefault()} /> </SideNavigation.NestedGroup> <SideNavigation.NestedGroup label="Alternative Christmas"> <SideNavigation.NestedItem active="section" href="#" label="West Coast" onClick={({ event }) => event.preventDefault()} /> <SideNavigation.NestedItem href="#" label="East Coast" onClick={({ event }) => event.preventDefault()} /> </SideNavigation.NestedGroup> </SideNavigation.Group> <SideNavigation.Group display="static" icon="people" label="Halloween" > <SideNavigation.NestedItem href="#" label="East Coast" onClick={({ event }) => event.preventDefault()} /> <SideNavigation.NestedItem href="#" label="West Coast" onClick={({ event }) => event.preventDefault()} /> </SideNavigation.Group> </SideNavigation.Section> </SideNavigation> </Box> ); }
Group display
Group display can be:
- static: Group is expanded by default and there isn't expanding/collapsing behavior
- expandable: Group is expandable and all items are initially collapsed except groups with active children.
When display='expandable'
, we can manage the state of each group's collapsing/expanded state by setting SideNavigation.Group and SideNavigation.NestedGroup as controlled components.
To work as controlled components, set expand
prop to a boolean value. If not passed or set to "undefined", they stay uncontrolled.
Beware that when controlled, the list path to the active item is not automatically expanded.
import React from 'react'; import { Box, SideNavigation } from 'gestalt'; export default function Example() { return ( <Box height="100%" width={280}> <SideNavigation accessibilityLabel="Nested items example" showBorder> <SideNavigation.Group display="static" icon="people" label="Christmas"> <SideNavigation.NestedItem href="#" label="Luxury Christmas" onClick={({ event }) => event.preventDefault()} /> <SideNavigation.NestedGroup display="static" label="Classic Christmas" > <SideNavigation.NestedItem href="#" label="West Coast" onClick={({ event }) => event.preventDefault()} /> </SideNavigation.NestedGroup> <SideNavigation.NestedItem href="#" label="Luxury Christmas" onClick={({ event }) => event.preventDefault()} /> </SideNavigation.Group> </SideNavigation> </Box> ); }
import React from 'react'; import { Box, SideNavigation } from 'gestalt'; export default function Example() { return ( <Box height="100%" width={280}> <SideNavigation accessibilityLabel="Nested items example" showBorder> <SideNavigation.Group icon="people" label="Christmas"> <SideNavigation.NestedItem href="#" label="Luxury Christmas" onClick={({ event }) => event.preventDefault()} /> <SideNavigation.NestedGroup label="Classic Christmas"> <SideNavigation.NestedItem href="#" label="West Coast" onClick={({ event }) => event.preventDefault()} /> </SideNavigation.NestedGroup> <SideNavigation.NestedItem href="#" label="Luxury Christmas" onClick={({ event }) => event.preventDefault()} /> </SideNavigation.Group> </SideNavigation> </Box> ); }
import { useState } from 'react'; import { Box, SideNavigation } from 'gestalt'; export default function Example() { const [expandedElements, setExpandedElements] = useState([ 'Christmas', 'Classic Christmas', ]); const handleOnExpand = (name) => ({ expanded }) => { if (expanded) { setExpandedElements([...expandedElements, name]); } else { setExpandedElements(expandedElements.filter((value) => value !== name)); } }; return ( <Box height="100%" width={280}> <SideNavigation accessibilityLabel="Nested items example" showBorder> <SideNavigation.Group display="expandable" expanded={expandedElements.includes('Christmas')} icon="people" label="Christmas" onExpand={handleOnExpand('Christmas')} > <SideNavigation.NestedItem href="#" label="Luxury Christmas" onClick={({ event }) => event.preventDefault()} /> <SideNavigation.NestedGroup display="expandable" expanded={expandedElements.includes('Classic Christmas')} label="Classic Christmas" onExpand={handleOnExpand('Classic Christmas')} > <SideNavigation.NestedItem href="#" label="West Coast" onClick={({ event }) => event.preventDefault()} /> </SideNavigation.NestedGroup> <SideNavigation.NestedItem href="#" label="Luxury Christmas" onClick={({ event }) => event.preventDefault()} /> </SideNavigation.Group> </SideNavigation> </Box> ); }
Group link display
Group items can also have links and navigate to a page.
import React, { useState } from 'react'; import { Box, SideNavigation } from 'gestalt'; export default function Example() { const [page, setPage] = useState('1'); return ( <Box height="100%" width={280}> <SideNavigation accessibilityLabel="Nested items example" showBorder> <SideNavigation.Group active={page === '1' ? 'page' : undefined} display="static" href="#" icon="people" label="Christmas" onClick={({ event }) => { event.preventDefault(); setPage('1'); }} > <SideNavigation.NestedItem active={page === '2' ? 'page' : undefined} href="#" label="Luxury Christmas" onClick={({ event }) => { event.preventDefault(); setPage('2'); }} /> <SideNavigation.NestedGroup active={page === '3' ? 'page' : undefined} display="static" href="#" label="Classic Christmas" onClick={({ event }) => { event.preventDefault(); setPage('3'); }} > <SideNavigation.NestedItem active={page === '4' ? 'page' : undefined} href="#" label="West Coast" onClick={({ event }) => { event.preventDefault(); setPage('4'); }} /> </SideNavigation.NestedGroup> <SideNavigation.NestedItem active={page === '5' ? 'page' : undefined} href="#" label="Luxury Christmas" onClick={({ event }) => { event.preventDefault(); setPage('5'); }} /> </SideNavigation.Group> </SideNavigation> </Box> ); }
import React, { useState } from 'react'; import { Box, SideNavigation } from 'gestalt'; export default function Example() { const [page, setPage] = useState('1'); return ( <Box height="100%" width={280}> <SideNavigation accessibilityLabel="Nested items example" showBorder> <SideNavigation.Group active={page === '1' ? 'page' : undefined} href="#" icon="people" label="Christmas" onClick={({ event }) => { event.preventDefault(); setPage('1'); }} > <SideNavigation.NestedItem active={page === '2' ? 'page' : undefined} href="#" label="Luxury Christmas" onClick={({ event }) => { event.preventDefault(); setPage('2'); }} /> <SideNavigation.NestedGroup active={page === '3' ? 'page' : undefined} href="#" label="Classic Christmas" onClick={({ event }) => { event.preventDefault(); setPage('3'); }} > <SideNavigation.NestedItem active={page === '4' ? 'page' : undefined} href="#" label="West Coast" onClick={({ event }) => { event.preventDefault(); setPage('4'); }} /> </SideNavigation.NestedGroup> <SideNavigation.NestedItem active={page === '5' ? 'page' : undefined} href="#" label="Luxury Christmas" onClick={({ event }) => { event.preventDefault(); setPage('5'); }} /> </SideNavigation.Group> </SideNavigation> </Box> ); }
Subcomponent composability
SideNavigation requires its own subcomponents as children to build the list of navigation items.
When building SideNavigation, we might want to render different combinations of subcomponents conditionally. SideNavigation supports simple conditional rendering of subcomponents lists wrapped in React.Fragment as well as consecutive arrays of subcomponent arrays. See the example below which illustrates both of these cases. More logic complexity might break the correct SideNavigation behavior.
import React, { useState } from 'react'; import { Box, SideNavigation } from 'gestalt'; export default function Example() { const [page, setPage] = useState(''); const someCondition = true; return ( <Box height="100%" width={300}> <SideNavigation accessibilityLabel="Subcomponent composability example" showBorder > {someCondition && ( <SideNavigation.TopItem active={page === 'Trends' ? 'page' : undefined} href="#" icon="ads-stats" label="Trends" onClick={({ event }) => { event.preventDefault(); setPage('Trends'); }} /> )} <SideNavigation.Section label="Analytics"> {someCondition && ( <SideNavigation.TopItem active={page === 'Reporting' ? 'page' : undefined} href="#" icon="ads-stats" label="Reporting" onClick={({ event }) => { event.preventDefault(); setPage('Reporting'); }} /> )} {someCondition && ( <SideNavigation.TopItem active={page === 'Conversions' ? 'page' : undefined} href="#" icon="replace" label="Conversions" onClick={({ event }) => { event.preventDefault(); setPage('Conversions'); }} /> )} </SideNavigation.Section> <SideNavigation.Section label="Audiences"> <SideNavigation.Group active={page === 'Christmas' ? 'page' : undefined} href="#" icon="people" label="Christmas" onClick={({ event }) => { event.preventDefault(); setPage('Christmas'); }} > <SideNavigation.NestedItem active={page === 'Luxury Christmas' ? 'page' : undefined} href="#" label="Luxury Christmas" onClick={({ event }) => { event.preventDefault(); setPage('Luxury Christmas'); }} /> <SideNavigation.NestedGroup active={page === 'Classic Christmas' ? 'page' : undefined} href="#" label="Classic Christmas" onClick={({ event }) => { event.preventDefault(); setPage('Classic Christmas'); }} > {['West Coast', 'East Coast'].map((x) => ( <SideNavigation.NestedItem key={`xmas${x}`} active={page === `Classic ${x}` ? 'page' : undefined} href="#" label={x} onClick={({ event }) => { event.preventDefault(); setPage(`Classic ${x}`); }} /> ))} </SideNavigation.NestedGroup> <SideNavigation.NestedGroup label="Alternative Christmas"> {['West Coast', 'East Coast'].map((x) => ( <SideNavigation.NestedItem key={`xmas${x}`} active={page === `Alternative ${x}` ? 'page' : undefined} href="#" label={x} onClick={({ event }) => { event.preventDefault(); setPage(`Alternative ${x}`); }} /> ))} {['Southern', 'NorthEast'].map((x) => ( <SideNavigation.NestedItem key={`xmas${x}`} active={page === `Alternative ${x}` ? 'page' : undefined} href="#" label={x} onClick={({ event }) => { event.preventDefault(); setPage(`Alternative ${x}`); }} /> ))} </SideNavigation.NestedGroup> </SideNavigation.Group> <SideNavigation.Group icon="people" label="Halloween"> {['West Coast', 'East Coast'].map((x) => ( <SideNavigation.NestedItem key={`halloween${x}`} active={page === `Halloween ${x}` ? 'page' : undefined} href="#" label={x} onClick={({ event }) => { event.preventDefault(); setPage(`Halloween ${x}`); }} /> ))} </SideNavigation.Group> </SideNavigation.Section> </SideNavigation> </Box> ); }
Collapsible
Providing collapsed
prop to SideNavigation makes the component collapsible. Collapsible variant of SideNavigation is a controlled component and it has expand/collapse icon button at the top. Clicking the icon button reveals a complete list of navigation options when expanded and minimizes these options, often to a series of compact icons or completely hidden when collapsed. This variant is not available for mobile.
It is recommended the wrapper to be sticky
(not fixed
) so that it stays visible and keeps its position "relative" to other elements. Being sticky means SideNavigation's can naturally shift the adjacent elements/components.
When collapsed, if all the navigation items have icons, SideNavigation is displayed as a compact set of icons.
import React, { useState } from 'react'; import { Box, Heading, SideNavigation } from 'gestalt'; export default function Example() { const [page, setPage] = useState(''); const [collapsed, setCollapsed] = useState(false); return ( <Box display="flex" height="100%" overflow="auto"> {/* It is recommended the wrapper to be sticky. */} <div style={{ position: 'sticky', top: 0 }}> <SideNavigation accessibilityLabel="Collapsible example" collapsed={collapsed} onCollapse={setCollapsed} showBorder > <SideNavigation.TopItem active={page === '1' ? 'page' : undefined} href="#" icon="trending" label="Trends" notificationAccessibilityLabel="New data available" onClick={({ event }) => { event.preventDefault(); setPage('1'); }} primaryAction={{ icon: 'ellipsis', tooltip: { text: 'Mark as read' }, }} /> <SideNavigation.TopItem active={page === '2' ? 'page' : undefined} badge={{ text: 'New', type: 'success' }} counter={{ number: '10', accessibilityLabel: 'New details' }} href="#" icon="business-hierarchy" label="Business Details" onClick={({ event }) => { event.preventDefault(); setPage('2'); }} /> <SideNavigation.Section label="Public Holidays"> <SideNavigation.Group icon="people" label="Christmas"> <SideNavigation.NestedItem active={page === '3' ? 'page' : undefined} href="#" label="Luxury Christmas" onClick={({ event }) => { event.preventDefault(); setPage('3'); }} /> <SideNavigation.NestedItem active={page === '4' ? 'page' : undefined} href="#" label="Luxury Christmas" onClick={({ event }) => { event.preventDefault(); setPage('4'); }} /> <SideNavigation.NestedGroup label="Classic Christmas"> <SideNavigation.NestedItem active={page === '5' ? 'page' : undefined} href="#" label="West Coast" onClick={({ event }) => { event.preventDefault(); setPage('5'); }} /> </SideNavigation.NestedGroup> </SideNavigation.Group> <SideNavigation.TopItem active={page === '6' ? 'page' : undefined} href="#" icon="overview" label="Public profile" notificationAccessibilityLabel="Needs your attention" onClick={({ event }) => { event.preventDefault(); setPage('6'); }} /> <SideNavigation.TopItem active={page === '7' ? 'page' : undefined} href="#" icon="workflow-status-unstarted" label="Personal information" onClick={({ event }) => { event.preventDefault(); setPage('7'); }} /> </SideNavigation.Section> <SideNavigation.Section label="Contacts"> <SideNavigation.TopItem active={page === '8' ? 'page' : undefined} href="#" icon="phone" label="Contact Information" onClick={({ event }) => { event.preventDefault(); setPage('8'); }} /> <SideNavigation.TopItem active={page === '9' ? 'page' : undefined} href="#" icon="history" label="Other Details" onClick={({ event }) => { event.preventDefault(); setPage('9'); }} /> </SideNavigation.Section> </SideNavigation> </div> <Box height={800} padding={4}> <Heading size="500">Page main content</Heading> </Box> </Box> ); }
If some of the navigation items don't have icons, those items are collapsed into an ellipsis. Clicking on ellipses expands the SideNavigation in preview mode and when an item is selected, the component is collapsed again.
import React, { useState } from 'react'; import { Box, Heading, SideNavigation } from 'gestalt'; export default function Example() { const [page, setPage] = useState(''); const [collapsed, setCollapsed] = useState(false); return ( <Box display="flex" height="100%" overflow="auto"> {/* It is recommended the wrapper to be sticky. */} <div style={{ position: 'sticky', top: 0 }}> <SideNavigation accessibilityLabel="Collapsible example" collapsed={collapsed} onCollapse={setCollapsed} showBorder > <SideNavigation.TopItem active={page === '1' ? 'page' : undefined} href="#" icon="trending" label="Trends" notificationAccessibilityLabel="New data available" onClick={({ event }) => { event.preventDefault(); setPage('1'); }} primaryAction={{ icon: 'ellipsis', tooltip: { text: 'Mark as read' }, }} /> <SideNavigation.TopItem active={page === '2' ? 'page' : undefined} badge={{ text: 'New', type: 'success' }} counter={{ number: '10', accessibilityLabel: 'New details' }} href="#" icon="business-hierarchy" label="Business Details" onClick={({ event }) => { event.preventDefault(); setPage('2'); }} /> <SideNavigation.Section label="Public Holidays"> <SideNavigation.Group label="Christmas"> <SideNavigation.NestedItem active={page === '3' ? 'page' : undefined} href="#" label="Luxury Christmas" onClick={({ event }) => { event.preventDefault(); setPage('3'); }} /> <SideNavigation.NestedItem active={page === '4' ? 'page' : undefined} href="#" label="Luxury Christmas" onClick={({ event }) => { event.preventDefault(); setPage('4'); }} /> <SideNavigation.NestedGroup label="Classic Christmas"> <SideNavigation.NestedItem active={page === '5' ? 'page' : undefined} href="#" label="West Coast" onClick={({ event }) => { event.preventDefault(); setPage('5'); }} /> </SideNavigation.NestedGroup> </SideNavigation.Group> <SideNavigation.TopItem active={page === '6' ? 'page' : undefined} href="#" icon="overview" label="Public profile" notificationAccessibilityLabel="Needs your attention" onClick={({ event }) => { event.preventDefault(); setPage('6'); }} /> <SideNavigation.TopItem active={page === '7' ? 'page' : undefined} href="#" icon="workflow-status-unstarted" label="Personal information" onClick={({ event }) => { event.preventDefault(); setPage('7'); }} /> </SideNavigation.Section> <SideNavigation.Section label="Contacts"> <SideNavigation.TopItem active={page === '8' ? 'page' : undefined} href="#" icon="phone" label="Contact Information" onClick={({ event }) => { event.preventDefault(); setPage('8'); }} /> <SideNavigation.TopItem active={page === '9' ? 'page' : undefined} href="#" label="Other Details" onClick={({ event }) => { event.preventDefault(); setPage('9'); }} /> </SideNavigation.Section> </SideNavigation> </div> <Box height={800} padding={4}> <Heading size="500">Page main content</Heading> </Box> </Box> ); }
When collapsed, the header and the footer of SideNavigation should be rendered accordingly.
import React, { useState } from 'react'; import { Box, Flex, Heading, Icon, SideNavigation } from 'gestalt'; export default function Example() { const [page, setPage] = useState(''); const [collapsed, setCollapsed] = useState(false); const [preview, setPreview] = useState(false); return ( <Box display="flex" height="100%" overflow="auto"> {/* It is recommended the wrapper to be sticky. */} <div style={{ position: 'sticky', top: 0 }}> <SideNavigation accessibilityLabel="Collapsible example" collapsed={collapsed} header={ collapsed && !preview ? ( <Flex alignItems="center" gap={2} justifyContent="center"> <Flex.Item> <Icon accessibilityLabel="" color="brandPrimary" icon="pinterest" size={36} /> </Flex.Item> </Flex> ) : ( <Flex alignItems="center" gap={2}> <Flex.Item> <Icon accessibilityLabel="" color="brandPrimary" icon="pinterest" size={36} /> </Flex.Item> <Flex.Item> <Heading size="400">Pinterest Business</Heading> </Flex.Item> </Flex> ) } onCollapse={setCollapsed} onPreview={setPreview} showBorder > <SideNavigation.TopItem active={page === '1' ? 'page' : undefined} href="#" icon="trending" label="Trends" notificationAccessibilityLabel="New data available" onClick={({ event }) => { event.preventDefault(); setPage('1'); }} primaryAction={{ icon: 'ellipsis', tooltip: { text: 'Mark as read' }, }} /> <SideNavigation.TopItem active={page === '2' ? 'page' : undefined} badge={{ text: 'New', type: 'success' }} counter={{ number: '10', accessibilityLabel: 'New details' }} href="#" icon="business-hierarchy" label="Business Details" onClick={({ event }) => { event.preventDefault(); setPage('2'); }} /> <SideNavigation.Section label="Contacts"> <SideNavigation.TopItem active={page === '8' ? 'page' : undefined} href="#" icon="phone" label="Contact Information" onClick={({ event }) => { event.preventDefault(); setPage('8'); }} /> <SideNavigation.TopItem active={page === '9' ? 'page' : undefined} href="#" icon="history" label="Other Details" onClick={({ event }) => { event.preventDefault(); setPage('9'); }} /> </SideNavigation.Section> </SideNavigation> </div> <Box height={800} padding={4}> <Heading size="500">Page main content</Heading> </Box> </Box> ); }
If none of the SideNavigation items have icons, the component is collapsed only with expand icon button.
import React, { useState } from 'react'; import { Box, Heading, SideNavigation } from 'gestalt'; export default function Example() { const [page, setPage] = useState(''); const [collapsed, setCollapsed] = useState(false); return ( <Box display="flex" height="100%" overflow="auto"> {/* It is recommended the wrapper to be sticky. */} <div style={{ position: 'sticky', top: 0 }}> <SideNavigation accessibilityLabel="Collapsible example" collapsed={collapsed} onCollapse={setCollapsed} showBorder > <SideNavigation.TopItem active={page === '1' ? 'page' : undefined} href="#" label="Trends" notificationAccessibilityLabel="New data available" onClick={({ event }) => { event.preventDefault(); setPage('1'); }} primaryAction={{ icon: 'ellipsis', tooltip: { text: 'Mark as read' }, }} /> <SideNavigation.TopItem active={page === '2' ? 'page' : undefined} badge={{ text: 'New', type: 'success' }} counter={{ number: '10', accessibilityLabel: 'New details' }} href="#" label="Business Details" onClick={({ event }) => { event.preventDefault(); setPage('2'); }} /> <SideNavigation.Section label="Public Holidays"> <SideNavigation.Group label="Christmas"> <SideNavigation.NestedItem active={page === '3' ? 'page' : undefined} href="#" label="Luxury Christmas" onClick={({ event }) => { event.preventDefault(); setPage('3'); }} /> <SideNavigation.NestedItem active={page === '4' ? 'page' : undefined} href="#" label="Luxury Christmas" onClick={({ event }) => { event.preventDefault(); setPage('4'); }} /> <SideNavigation.NestedGroup label="Classic Christmas"> <SideNavigation.NestedItem active={page === '5' ? 'page' : undefined} href="#" label="West Coast" onClick={({ event }) => { event.preventDefault(); setPage('5'); }} /> </SideNavigation.NestedGroup> </SideNavigation.Group> <SideNavigation.TopItem active={page === '6' ? 'page' : undefined} href="#" label="Public profile" notificationAccessibilityLabel="Needs your attention" onClick={({ event }) => { event.preventDefault(); setPage('6'); }} /> <SideNavigation.TopItem active={page === '7' ? 'page' : undefined} href="#" label="Personal information" onClick={({ event }) => { event.preventDefault(); setPage('7'); }} /> </SideNavigation.Section> <SideNavigation.Section label="Contacts"> <SideNavigation.TopItem active={page === '8' ? 'page' : undefined} href="#" label="Contact Information" onClick={({ event }) => { event.preventDefault(); setPage('8'); }} /> <SideNavigation.TopItem active={page === '9' ? 'page' : undefined} href="#" label="Other Details" onClick={({ event }) => { event.preventDefault(); setPage('9'); }} /> </SideNavigation.Section> </SideNavigation> </div> <Box height={800} padding={4}> <Heading size="500">Page main content</Heading> </Box> </Box> ); }
Mobile
SideNavigation requires DeviceTypeProvider to enable its mobile user interface. The example below shows the mobile platform UI and its implementation.
For mobile, title
and dismissButton
become required props.
Notice that the mobile UI requires logic to hide and show SideNavigation full width. If
Button or
TapArea control the visibility of SideNavigation, use accessibilityControls
so that screen reader users can identify the relationship between elements.
import { useState } from 'react'; import { Box, Button, DeviceTypeProvider, SideNavigation } from 'gestalt'; export default function Example() { const [showNav, setShowNav] = useState(false); return showNav ? ( <DeviceTypeProvider deviceType="mobile"> <Box bottom id="sidenavigation" left position="absolute" right top> <SideNavigation accessibilityLabel="Mobile device example" dismissButton={{ onDismiss: () => setShowNav(false), accessibilityLabel: 'Close navigation', }} mobileTitle="Advertisement" > <SideNavigation.TopItem href="#" icon="ads-stats" label="Reporting" onClick={({ event }) => event.preventDefault()} /> <SideNavigation.TopItem href="#" icon="replace" label="Conversions" onClick={({ event }) => event.preventDefault()} /> <SideNavigation.Section label="Audiences"> <SideNavigation.TopItem href="#" icon="people" label="Thanksgiving" onClick={({ event }) => event.preventDefault()} /> <SideNavigation.Group icon="people" label="Christmas"> <SideNavigation.NestedItem href="#" label="Luxury Christmas" onClick={({ event }) => event.preventDefault()} /> <SideNavigation.NestedGroup label="Classic Christmas"> <SideNavigation.NestedItem href="#" label="West Coast" onClick={({ event }) => event.preventDefault()} /> <SideNavigation.NestedItem href="#" label="East Coast" onClick={({ event }) => event.preventDefault()} /> </SideNavigation.NestedGroup> <SideNavigation.NestedGroup label="Alternative Christmas"> <SideNavigation.NestedItem href="#" label="West Coast" onClick={({ event }) => event.preventDefault()} /> <SideNavigation.NestedItem href="#" label="East Coast" onClick={({ event }) => event.preventDefault()} /> </SideNavigation.NestedGroup> </SideNavigation.Group> <SideNavigation.Group display="static" icon="people" label="Halloween" > <SideNavigation.NestedItem href="#" label="East Coast" onClick={({ event }) => event.preventDefault()} /> <SideNavigation.NestedItem href="#" label="West Coast" onClick={({ event }) => event.preventDefault()} /> </SideNavigation.Group> </SideNavigation.Section> </SideNavigation> </Box> </DeviceTypeProvider> ) : ( <Box padding={2}> <Button accessibilityControls="sidenavigation" accessibilityLabel="Show navigation" color="red" onClick={() => setShowNav(true)} size="lg" text="Show navigation" /> </Box> ); }
Writing
- Keep menu item labels brief, remembering that length is language-dependent
- Use complete sentences or lengthy descriptions
- Be redundant; use a section header if you find yourself repeating the same word over and over again in labels
Component quality checklist
Quality item | Status | Status description |
---|---|---|
Figma Library | Ready | Component is available in Figma for web and mobile web. |
Responsive Web | Ready | Component responds to changing viewport sizes in web and mobile web. |
Related
Tabs
Used to navigate between urls and placed horizontally. Tabs can be used when there are 2–5 URLs to navigate between and can be used as a sub-navigation after the top nav bar or after a SideNav.
SegmentedControl
SegmentedControl is used to select between different views or arrangements of related content. Like Tabs, this control is horizontal, but unlike tabs, it doesn’t navigated between URLs.
Dropdown
A custom menu to select URLs to navigate to, or actions to take. This is always triggered by a button.
PageHeader
For pages with a main top nav bar, every SideNav should have a PageHeader to announce the main page that the navigation items belong to. Exceptions are internal tools or developer platform interfaces where the SideNav is the main navigation.