Sidebar
The side navigation of an app, open while people work.
Left out of Brand expressive Sidebar is for apps people move around all session. Brand expressive avoids tools people use for hours, and a visit lasts a few minutes at most. Use instead: Navigation menu, Drawer
See it live
npm run storybookWhen to use it
- Use it when: Apps with several sections people move between all session.
- Not when: A website's main navigation (navigation menu), or a few sections that fit in tabs.
Instead:
- Navigation menu: Website navigation.
- Tabs: Views of one thing.
Variants
What each variant is for in any design system, then what Brand expressive decided and why. Each sample is the live story with that variant set.
defaultvariantNot decided yetWhat it is for
Menu items with no border; hover shows the item.
In Brand expressive
Not decided yet.
outlinevariantNot decided yetWhat it is for
Menu items with a border.
In Brand expressive
Not decided yet.
defaultsizeNot decided yetWhat it is for
The normal row height.
In Brand expressive
Not decided yet.
smsizeNot decided yetWhat it is for
A smaller row.
In Brand expressive
Not decided yet.
lgsizeNot decided yetWhat it is for
A taller row with room for an icon and two lines.
In Brand expressive
Not decided yet.
Words
- Headlines are short and bold. Three to six words.
- Verbs that move: Join, Try, Go.
- Playful in headlines, plain in errors.
- Use: Join, Drop, Go, Love. Avoid: Synergy, Leverage, Kindly.
The labels components use, from the voice tokens:
content.action.commit: Gocontent.action.cancel: Not nowcontent.action.destroy: Removecontent.action.retry: Try againcontent.action.empty-action: Explore the drop
See Voice and tone for the whole voice.
Accessibility and keyboard
Test before you ship:
- It is a navigation landmark; the current section is marked; collapsing keeps names for icons. undefined
Use it in code
npx open-ds add sidebar
The component reads only component keys and semantic tokens, so it follows the brand and mode on <html>.
Tokens it reads
Sidebar reads 113 tokens of its own, each an alias of a semantic token. Each row is one part: its own token, the semantic it aliases, and the value it ends at. Change a semantic and every component that reads it follows; override one of Sidebar's tokens to change Sidebar alone.
Brand expressive decides what changes when you switch theme. Here a switch changes colors only, so the marked rows differ between light and dark; everything else holds steady.
| Part | Its token and the semantic it aliases | Value |
|---|---|---|
| Wrapper | ||
| Fill Changes with theme | component.sidebar.wrapper.backgroundcolor.surface.defaultvar(--sidebar-wrapper-background) | Lighttaupe.light.0:#FFFFFFDarktaupe.dark.50:#1F1411 |
| Sidebar | ||
| Fill Changes with theme | component.sidebar.backgroundcolor.surface.defaultvar(--sidebar-background) | Lighttaupe.light.0:#FFFFFFDarktaupe.dark.50:#1F1411 |
| Text Changes with theme | component.sidebar.labelcolor.text.primaryvar(--sidebar-label) | Lighttaupe.light.900:#1F1411Darktaupe.dark.900:#FFF8F3 |
| Padding | component.sidebar.paddingcomponent-spacing-map.x2var(--sidebar-padding) | space.8:0.5rem |
| Background hover Changes with theme on hover | component.sidebar.background-hovercolor.surface.defaultvar(--sidebar-background-hover) | Lighttaupe.light.0:#FFFFFFDarktaupe.dark.50:#1F1411 |
| Corner | component.sidebar.radiusradius.controlvar(--sidebar-radius) | radius.999:9999px |
| Text size | component.sidebar.font-sizetype.body.font-sizevar(--sidebar-font-size) | font.size.17:1.0625rem |
| Focus ring Changes with theme | component.sidebar.focus-ringcolor.border.focusvar(--sidebar-focus-ring) | Lightpink.light.600:#D61F7ADarkpink.dark.600:#F59ACA |
| Padding right | component.sidebar.padding-rightcomponent-spacing-map.x8var(--sidebar-padding-right) | space.64:4rem |
| Size | component.sidebar.sizesize.control.defaultvar(--sidebar-size) | size.52:3.25rem |
| Background hover 2 Changes with theme on hover | component.sidebar.background-hover-2color.surface.sunkenvar(--sidebar-background-hover-2) | Lighttaupe.light.100:#FCEFE6Darktaupe.dark.100:#33241F |
| Label hover Changes with theme on hover | component.sidebar.label-hovercolor.text.primaryvar(--sidebar-label-hover) | Lighttaupe.light.900:#1F1411Darktaupe.dark.900:#FFF8F3 |
| Background active Changes with theme | component.sidebar.background-activecolor.surface.sunkenvar(--sidebar-background-active) | Lighttaupe.light.100:#FCEFE6Darktaupe.dark.100:#33241F |
| Label active Changes with theme | component.sidebar.label-activecolor.text.primaryvar(--sidebar-label-active) | Lighttaupe.light.900:#1F1411Darktaupe.dark.900:#FFF8F3 |
| Disabled opacity disabled when disabled | component.sidebar.disabled-opacity-disabledopacity.disabledvar(--sidebar-disabled-opacity-disabled) | opacity.40:0.4 |
| Background 2 Changes with theme | component.sidebar.background-2color.surface.sunkenvar(--sidebar-background-2) | Lighttaupe.light.100:#FCEFE6Darktaupe.dark.100:#33241F |
| Weight | component.sidebar.font-weighttype.label.font-weightvar(--sidebar-font-weight) | font.weight.700:700 |
| Focus | component.sidebar.focusborder-width.focusvar(--sidebar-focus) | border-width.3:3px |
| Background open hover Changes with theme when open, on hover | component.sidebar.background-open-hovercolor.surface.sunkenvar(--sidebar-background-open-hover) | Lighttaupe.light.100:#FCEFE6Darktaupe.dark.100:#33241F |
| Label open hover Changes with theme when open, on hover | component.sidebar.label-open-hovercolor.text.primaryvar(--sidebar-label-open-hover) | Lighttaupe.light.900:#1F1411Darktaupe.dark.900:#FFF8F3 |
| Icon size | component.sidebar.icon-sizesize.iconvar(--sidebar-icon-size) | size.20:1.25rem |
| Focus ring focus Changes with theme on focus | component.sidebar.focus-ring-focuscolor.border.focusvar(--sidebar-focus-ring-focus) | Lightpink.light.600:#D61F7ADarkpink.dark.600:#F59ACA |
| Focus ring offset focus Changes with theme on focus | component.sidebar.focus-ring-offset-focuscolor.surface.canvasvar(--sidebar-focus-ring-offset-focus) | Lighttaupe.light.50:#FFF8F3Darktaupe.dark.0:#120B09 |
| Height | component.sidebar.heightsize.iconvar(--sidebar-height) | size.20:1.25rem |
| Font size 2 | component.sidebar.font-size-2type.caption.font-sizevar(--sidebar-font-size-2) | font.size.14:0.875rem |
| Gap | ||
| Speed | component.sidebar.gap.durationmotion.duration.feedbackvar(--sidebar-gap-duration) | duration.fast:120ms |
| Value | component.sidebar.gapspace.gap.defaultvar(--sidebar-gap) | space.16:1rem |
| Container | ||
| Speed | component.sidebar.container.durationmotion.duration.feedbackvar(--sidebar-container-duration) | duration.fast:120ms |
| Inner | ||
| Fill Changes with theme | component.sidebar.inner.backgroundcolor.surface.defaultvar(--sidebar-inner-background) | Lighttaupe.light.0:#FFFFFFDarktaupe.dark.50:#1F1411 |
| Corner | component.sidebar.inner.radiusradius.containervar(--sidebar-inner-radius) | radius.24:1.5rem |
| Border Changes with theme | component.sidebar.inner.bordercolor.border.defaultvar(--sidebar-inner-border) | Lighttaupe.light.200:#F2DCCFDarktaupe.dark.100:#33241F |
| Shadow Changes with theme | component.sidebar.inner.shadowelevation.cardvar(--sidebar-inner-shadow) | Lightshadow.cardDarkshadow.card-dark |
| Rail | ||
| Background hover Changes with theme on hover | component.sidebar.rail.background-hovercolor.border.defaultvar(--sidebar-rail-background-hover) | Lighttaupe.light.200:#F2DCCFDarktaupe.dark.100:#33241F |
| Inset | ||
| Fill Changes with theme | component.sidebar.inset.backgroundcolor.surface.canvasvar(--sidebar-inset-background) | Lighttaupe.light.50:#FFF8F3Darktaupe.dark.0:#120B09 |
| Corner | component.sidebar.inset.radiusradius.containervar(--sidebar-inset-radius) | radius.24:1.5rem |
| Shadow Changes with theme | component.sidebar.inset.shadowelevation.cardvar(--sidebar-inset-shadow) | Lightshadow.cardDarkshadow.card-dark |
| Input | ||
| Height | component.sidebar.input.heightsize.control.defaultvar(--sidebar-input-height) | size.52:3.25rem |
| Fill Changes with theme | component.sidebar.input.backgroundcolor.surface.canvasvar(--sidebar-input-background) | Lighttaupe.light.50:#FFF8F3Darktaupe.dark.0:#120B09 |
| Header | ||
| Gap | component.sidebar.header.gapspace.gap.defaultvar(--sidebar-header-gap) | space.16:1rem |
| Padding | component.sidebar.header.paddingcomponent-spacing-map.x2var(--sidebar-header-padding) | space.8:0.5rem |
| Footer | ||
| Gap | component.sidebar.footer.gapspace.gap.defaultvar(--sidebar-footer-gap) | space.16:1rem |
| Padding | component.sidebar.footer.paddingcomponent-spacing-map.x2var(--sidebar-footer-padding) | space.8:0.5rem |
| Separator | ||
| Fill Changes with theme | component.sidebar.separator.backgroundcolor.border.defaultvar(--sidebar-separator-background) | Lighttaupe.light.200:#F2DCCFDarktaupe.dark.100:#33241F |
| Content | ||
| Gap | component.sidebar.content.gapspace.gap.defaultvar(--sidebar-content-gap) | space.16:1rem |
| Group | ||
| Padding | component.sidebar.group.paddingcomponent-spacing-map.x2var(--sidebar-group-padding) | space.8:0.5rem |
| Label height | component.sidebar.group.label.heightsize.control.defaultvar(--sidebar-group-label-height) | size.52:3.25rem |
| Label radius | component.sidebar.group.label.radiusradius.controlvar(--sidebar-group-label-radius) | radius.999:9999px |
| Label padding x | component.sidebar.group.label.padding-xcomponent-spacing-map.x2var(--sidebar-group-label-padding-x) | space.8:0.5rem |
| Label font size | component.sidebar.group.label.font-sizetype.caption.font-sizevar(--sidebar-group-label-font-size) | font.size.14:0.875rem |
| Label font weight | component.sidebar.group.label.font-weighttype.label.font-weightvar(--sidebar-group-label-font-weight) | font.weight.700:700 |
| Label label Changes with theme | component.sidebar.group.label.labelcolor.text.primaryvar(--sidebar-group-label-label) | Lighttaupe.light.900:#1F1411Darktaupe.dark.900:#FFF8F3 |
| Label focus ring Changes with theme | component.sidebar.group.label.focus-ringcolor.border.focusvar(--sidebar-group-label-focus-ring) | Lightpink.light.600:#D61F7ADarkpink.dark.600:#F59ACA |
| Label duration | component.sidebar.group.label.durationmotion.duration.feedbackvar(--sidebar-group-label-duration) | duration.fast:120ms |
| Label icon size | component.sidebar.group.label.icon-sizesize.iconvar(--sidebar-group-label-icon-size) | size.20:1.25rem |
| Label focus on focus | component.sidebar.group.label.focusborder-width.focusvar(--sidebar-group-label-focus) | border-width.3:3px |
| Label focus ring focus Changes with theme on focus | component.sidebar.group.label.focus-ring-focuscolor.border.focusvar(--sidebar-group-label-focus-ring-focus) | Lightpink.light.600:#D61F7ADarkpink.dark.600:#F59ACA |
| Label focus ring offset focus Changes with theme on focus | component.sidebar.group.label.focus-ring-offset-focuscolor.surface.canvasvar(--sidebar-group-label-focus-ring-offset-focus) | Lighttaupe.light.50:#FFF8F3Darktaupe.dark.0:#120B09 |
| Action radius | component.sidebar.group.action.radiusradius.controlvar(--sidebar-group-action-radius) | radius.999:9999px |
| Action label Changes with theme | component.sidebar.group.action.labelcolor.text.primaryvar(--sidebar-group-action-label) | Lighttaupe.light.900:#1F1411Darktaupe.dark.900:#FFF8F3 |
| Action focus ring Changes with theme | component.sidebar.group.action.focus-ringcolor.border.focusvar(--sidebar-group-action-focus-ring) | Lightpink.light.600:#D61F7ADarkpink.dark.600:#F59ACA |
| Action background hover Changes with theme on hover | component.sidebar.group.action.background-hovercolor.surface.sunkenvar(--sidebar-group-action-background-hover) | Lighttaupe.light.100:#FCEFE6Darktaupe.dark.100:#33241F |
| Action label hover Changes with theme on hover | component.sidebar.group.action.label-hovercolor.text.primaryvar(--sidebar-group-action-label-hover) | Lighttaupe.light.900:#1F1411Darktaupe.dark.900:#FFF8F3 |
| Action icon size | component.sidebar.group.action.icon-sizesize.iconvar(--sidebar-group-action-icon-size) | size.20:1.25rem |
| Action focus on focus | component.sidebar.group.action.focusborder-width.focusvar(--sidebar-group-action-focus) | border-width.3:3px |
| Action focus ring focus Changes with theme on focus | component.sidebar.group.action.focus-ring-focuscolor.border.focusvar(--sidebar-group-action-focus-ring-focus) | Lightpink.light.600:#D61F7ADarkpink.dark.600:#F59ACA |
| Action focus ring offset focus Changes with theme on focus | component.sidebar.group.action.focus-ring-offset-focuscolor.surface.canvasvar(--sidebar-group-action-focus-ring-offset-focus) | Lighttaupe.light.50:#FFF8F3Darktaupe.dark.0:#120B09 |
| Content font size | component.sidebar.group.content.font-sizetype.body.font-sizevar(--sidebar-group-content-font-size) | font.size.17:1.0625rem |
| Menu | ||
| Gap | component.sidebar.menu.gapspace.gap.tightvar(--sidebar-menu-gap) | space.8:0.5rem |
| Action radius | component.sidebar.menu.action.radiusradius.controlvar(--sidebar-menu-action-radius) | radius.999:9999px |
| Action label Changes with theme | component.sidebar.menu.action.labelcolor.text.primaryvar(--sidebar-menu-action-label) | Lighttaupe.light.900:#1F1411Darktaupe.dark.900:#FFF8F3 |
| Action focus ring Changes with theme | component.sidebar.menu.action.focus-ringcolor.border.focusvar(--sidebar-menu-action-focus-ring) | Lightpink.light.600:#D61F7ADarkpink.dark.600:#F59ACA |
| Action background hover Changes with theme on hover | component.sidebar.menu.action.background-hovercolor.surface.sunkenvar(--sidebar-menu-action-background-hover) | Lighttaupe.light.100:#FCEFE6Darktaupe.dark.100:#33241F |
| Action label hover Changes with theme on hover | component.sidebar.menu.action.label-hovercolor.text.primaryvar(--sidebar-menu-action-label-hover) | Lighttaupe.light.900:#1F1411Darktaupe.dark.900:#FFF8F3 |
| Action icon size | component.sidebar.menu.action.icon-sizesize.iconvar(--sidebar-menu-action-icon-size) | size.20:1.25rem |
| Action focus on focus | component.sidebar.menu.action.focusborder-width.focusvar(--sidebar-menu-action-focus) | border-width.3:3px |
| Action focus ring focus Changes with theme on focus | component.sidebar.menu.action.focus-ring-focuscolor.border.focusvar(--sidebar-menu-action-focus-ring-focus) | Lightpink.light.600:#D61F7ADarkpink.dark.600:#F59ACA |
| Action focus ring offset focus Changes with theme on focus | component.sidebar.menu.action.focus-ring-offset-focuscolor.surface.canvasvar(--sidebar-menu-action-focus-ring-offset-focus) | Lighttaupe.light.50:#FFF8F3Darktaupe.dark.0:#120B09 |
| Badge radius | component.sidebar.menu.badge.radiusradius.controlvar(--sidebar-menu-badge-radius) | radius.999:9999px |
| Badge padding x | component.sidebar.menu.badge.padding-xcomponent-spacing-map.x1var(--sidebar-menu-badge-padding-x) | space.4:0.25rem |
| Badge font size | component.sidebar.menu.badge.font-sizetype.caption.font-sizevar(--sidebar-menu-badge-font-size) | font.size.14:0.875rem |
| Badge font weight | component.sidebar.menu.badge.font-weighttype.label.font-weightvar(--sidebar-menu-badge-font-weight) | font.weight.700:700 |
| Badge label Changes with theme | component.sidebar.menu.badge.labelcolor.text.primaryvar(--sidebar-menu-badge-label) | Lighttaupe.light.900:#1F1411Darktaupe.dark.900:#FFF8F3 |
| Skeleton height | component.sidebar.menu.skeleton.heightsize.control.defaultvar(--sidebar-menu-skeleton-height) | size.52:3.25rem |
| Skeleton gap | component.sidebar.menu.skeleton.gapspace.gap.defaultvar(--sidebar-menu-skeleton-gap) | space.16:1rem |
| Skeleton radius | component.sidebar.menu.skeleton.radiusradius.controlvar(--sidebar-menu-skeleton-radius) | radius.999:9999px |
| Skeleton padding x | component.sidebar.menu.skeleton.padding-xcomponent-spacing-map.x2var(--sidebar-menu-skeleton-padding-x) | space.8:0.5rem |
| Sub gap | component.sidebar.menu.sub.gapspace.gap.tightvar(--sidebar-menu-sub-gap) | space.8:0.5rem |
| Sub border Changes with theme | component.sidebar.menu.sub.bordercolor.border.defaultvar(--sidebar-menu-sub-border) | Lighttaupe.light.200:#F2DCCFDarktaupe.dark.100:#33241F |
| Sub padding x | component.sidebar.menu.sub.padding-xcomponent-spacing-map.x3var(--sidebar-menu-sub-padding-x) | space.24:1.5rem |
| Sub padding y | component.sidebar.menu.sub.padding-ycomponent-spacing-map.hairlinevar(--sidebar-menu-sub-padding-y) | space.2:0.125rem |
| Sub button gap | component.sidebar.menu.sub.button.gapspace.gap.defaultvar(--sidebar-menu-sub-button-gap) | space.16:1rem |
| Sub button radius | component.sidebar.menu.sub.button.radiusradius.controlvar(--sidebar-menu-sub-button-radius) | radius.999:9999px |
| Sub button padding x | component.sidebar.menu.sub.button.padding-xcomponent-spacing-map.x2var(--sidebar-menu-sub-button-padding-x) | space.8:0.5rem |
| Sub button label Changes with theme | component.sidebar.menu.sub.button.labelcolor.text.primaryvar(--sidebar-menu-sub-button-label) | Lighttaupe.light.900:#1F1411Darktaupe.dark.900:#FFF8F3 |
| Sub button focus ring Changes with theme | component.sidebar.menu.sub.button.focus-ringcolor.border.focusvar(--sidebar-menu-sub-button-focus-ring) | Lightpink.light.600:#D61F7ADarkpink.dark.600:#F59ACA |
| Sub button background hover Changes with theme on hover | component.sidebar.menu.sub.button.background-hovercolor.surface.sunkenvar(--sidebar-menu-sub-button-background-hover) | Lighttaupe.light.100:#FCEFE6Darktaupe.dark.100:#33241F |
| Sub button label hover Changes with theme on hover | component.sidebar.menu.sub.button.label-hovercolor.text.primaryvar(--sidebar-menu-sub-button-label-hover) | Lighttaupe.light.900:#1F1411Darktaupe.dark.900:#FFF8F3 |
| Sub button background active Changes with theme | component.sidebar.menu.sub.button.background-activecolor.surface.sunkenvar(--sidebar-menu-sub-button-background-active) | Lighttaupe.light.100:#FCEFE6Darktaupe.dark.100:#33241F |
| Sub button label active Changes with theme | component.sidebar.menu.sub.button.label-activecolor.text.primaryvar(--sidebar-menu-sub-button-label-active) | Lighttaupe.light.900:#1F1411Darktaupe.dark.900:#FFF8F3 |
| Sub button disabled opacity disabled when disabled | component.sidebar.menu.sub.button.disabled-opacity-disabledopacity.disabledvar(--sidebar-menu-sub-button-disabled-opacity-disabled) | opacity.40:0.4 |
| Sub button icon size | component.sidebar.menu.sub.button.icon-sizesize.iconvar(--sidebar-menu-sub-button-icon-size) | size.20:1.25rem |
| Sub button focus on focus | component.sidebar.menu.sub.button.focusborder-width.focusvar(--sidebar-menu-sub-button-focus) | border-width.3:3px |
| Sub button focus ring focus Changes with theme on focus | component.sidebar.menu.sub.button.focus-ring-focuscolor.border.focusvar(--sidebar-menu-sub-button-focus-ring-focus) | Lightpink.light.600:#D61F7ADarkpink.dark.600:#F59ACA |
| Sub button focus ring offset focus Changes with theme on focus | component.sidebar.menu.sub.button.focus-ring-offset-focuscolor.surface.canvasvar(--sidebar-menu-sub-button-focus-ring-offset-focus) | Lighttaupe.light.50:#FFF8F3Darktaupe.dark.0:#120B09 |
| Default | ||
| Background hover Changes with theme | component.sidebar.default.background-hovercolor.surface.sunkenvar(--sidebar-default-background-hover) | Lighttaupe.light.100:#FCEFE6Darktaupe.dark.100:#33241F |
| Label hover Changes with theme on hover | component.sidebar.default.label-hovercolor.text.primaryvar(--sidebar-default-label-hover) | Lighttaupe.light.900:#1F1411Darktaupe.dark.900:#FFF8F3 |
| Height | component.sidebar.default.heightsize.control.defaultvar(--sidebar-default-height) | size.52:3.25rem |
| Text size | component.sidebar.default.font-sizetype.body.font-sizevar(--sidebar-default-font-size) | font.size.17:1.0625rem |
| Outline | ||
| Fill Changes with theme | component.sidebar.outline.backgroundcolor.surface.canvasvar(--sidebar-outline-background) | Lighttaupe.light.50:#FFF8F3Darktaupe.dark.0:#120B09 |
| Background hover Changes with theme on hover | component.sidebar.outline.background-hovercolor.surface.sunkenvar(--sidebar-outline-background-hover) | Lighttaupe.light.100:#FCEFE6Darktaupe.dark.100:#33241F |
| Label hover Changes with theme on hover | component.sidebar.outline.label-hovercolor.text.primaryvar(--sidebar-outline-label-hover) | Lighttaupe.light.900:#1F1411Darktaupe.dark.900:#FFF8F3 |
| Sm | ||
| Text size | component.sidebar.sm.font-sizetype.caption.font-sizevar(--sidebar-sm-font-size) | font.size.14:0.875rem |
| Lg | ||
| Text size | component.sidebar.lg.font-sizetype.body.font-sizevar(--sidebar-lg-font-size) | font.size.17:1.0625rem |
| From the system | ||
| Edge Changes with theme | color.border.default straight from the system, through --border | Lighttaupe.light.200 · #F2DCCFDarktaupe.dark.100 · #33241F |