Menubar
A row of menus, as in desktop apps.
Left out of Brand expressive Menubar is for dense desktop tools and not phones. Visitors come from social posts on their phones, and the site sections use navigation menu. Use instead: Navigation menu, Drawer
See it live
npm run storybookWhen to use it
- Use it when: A dense desktop-style tool with many commands grouped by menu.
- Not when: Website navigation (navigation menu), or phones.
Instead:
- Navigation menu: Site navigation, not commands.
- Dropdown menu: One menu from one button.
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
| Keyboard | What happens | Not |
|---|---|---|
| undefined | Arrow keys move between and within menus; Escape closes. | undefined |
Use it in code
npx open-ds add menubar
The component reads only component keys and semantic tokens, so it follows the brand and mode on <html>.
Tokens it reads
Menubar reads 78 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 Menubar's tokens to change Menubar 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 |
|---|---|---|
| Shared | ||
| Transition panels duration | component.transition.panels-durationmotion.duration.panelsvar(--transition-panels-duration) | duration.moderate:200ms |
| Menubar | ||
| Gap | component.menubar.gapspace.gap.tightvar(--menubar-gap) | space.8:0.5rem |
| Corner | component.menubar.radiusradius.controlvar(--menubar-radius) | radius.999:9999px |
| Fill Changes with theme | component.menubar.backgroundcolor.surface.canvasvar(--menubar-background) | Lighttaupe.light.50:#FFF8F3Darktaupe.dark.0:#120B09 |
| Padding | component.menubar.paddingcomponent-spacing-map.x1var(--menubar-padding) | space.4:0.25rem |
| Shadow Changes with theme | component.menubar.shadowelevation.cardvar(--menubar-shadow) | Lightshadow.cardDarkshadow.card-dark |
| Icon size | component.menubar.icon-sizesize.iconvar(--menubar-icon-size) | size.20:1.25rem |
| Height | component.menubar.heightsize.iconvar(--menubar-height) | size.20:1.25rem |
| Trigger | ||
| Corner | component.menubar.trigger.radiusradius.badgevar(--menubar-trigger-radius) | radius.999:9999px |
| Padding, left and right | component.menubar.trigger.padding-xcomponent-spacing-map.x2var(--menubar-trigger-padding-x) | space.8:0.5rem |
| Padding, top and bottom | component.menubar.trigger.padding-ycomponent-spacing-map.x1var(--menubar-trigger-padding-y) | space.4:0.25rem |
| Text size | component.menubar.trigger.font-sizetype.body.font-sizevar(--menubar-trigger-font-size) | font.size.17:1.0625rem |
| Weight | component.menubar.trigger.font-weighttype.label.font-weightvar(--menubar-trigger-font-weight) | font.weight.700:700 |
| Background focus Changes with theme on focus | component.menubar.trigger.background-focuscolor.surface.sunkenvar(--menubar-trigger-background-focus) | Lighttaupe.light.100:#FCEFE6Darktaupe.dark.100:#33241F |
| Label focus Changes with theme on focus | component.menubar.trigger.label-focuscolor.text.primaryvar(--menubar-trigger-label-focus) | Lighttaupe.light.900:#1F1411Darktaupe.dark.900:#FFF8F3 |
| Background open Changes with theme when open | component.menubar.trigger.background-opencolor.surface.sunkenvar(--menubar-trigger-background-open) | Lighttaupe.light.100:#FCEFE6Darktaupe.dark.100:#33241F |
| Label open Changes with theme when open | component.menubar.trigger.label-opencolor.text.primaryvar(--menubar-trigger-label-open) | Lighttaupe.light.900:#1F1411Darktaupe.dark.900:#FFF8F3 |
| Content | ||
| Corner | component.menubar.content.radiusradius.controlvar(--menubar-content-radius) | radius.999:9999px |
| Fill Changes with theme | component.menubar.content.backgroundcolor.surface.raisedvar(--menubar-content-background) | Lighttaupe.light.0:#FFFFFFDarktaupe.dark.100:#33241F |
| Padding | component.menubar.content.paddingcomponent-spacing-map.x1var(--menubar-content-padding) | space.4:0.25rem |
| Text Changes with theme | component.menubar.content.labelcolor.text.primaryvar(--menubar-content-label) | Lighttaupe.light.900:#1F1411Darktaupe.dark.900:#FFF8F3 |
| Shadow Changes with theme | component.menubar.content.shadowelevation.overlayvar(--menubar-content-shadow) | Lightshadow.overlayDarkshadow.overlay-dark |
| Item | ||
| Gap | component.menubar.item.gapspace.gap.defaultvar(--menubar-item-gap) | space.16:1rem |
| Corner | component.menubar.item.radiusradius.badgevar(--menubar-item-radius) | radius.999:9999px |
| Padding, left and right | component.menubar.item.padding-xcomponent-spacing-map.x2var(--menubar-item-padding-x) | space.8:0.5rem |
| Padding, top and bottom | component.menubar.item.padding-ycomponent-spacing-map.x2var(--menubar-item-padding-y) | space.8:0.5rem |
| Text size | component.menubar.item.font-sizetype.body.font-sizevar(--menubar-item-font-size) | font.size.17:1.0625rem |
| Background focus Changes with theme on focus | component.menubar.item.background-focuscolor.surface.sunkenvar(--menubar-item-background-focus) | Lighttaupe.light.100:#FCEFE6Darktaupe.dark.100:#33241F |
| Label focus Changes with theme on focus | component.menubar.item.label-focuscolor.text.primaryvar(--menubar-item-label-focus) | Lighttaupe.light.900:#1F1411Darktaupe.dark.900:#FFF8F3 |
| Disabled opacity disabled when disabled | component.menubar.item.disabled-opacity-disabledopacity.disabledvar(--menubar-item-disabled-opacity-disabled) | opacity.40:0.4 |
| Padding left | component.menubar.item.padding-leftcomponent-spacing-map.x8var(--menubar-item-padding-left) | space.64:4rem |
| Text Changes with theme destructive | component.menubar.item.labelcolor.status.dangervar(--menubar-item-label) | Lightred.light.600:#C42B2BDarkred.dark.600:#F28B8B |
| Background focus 2 Changes with theme destructive, on focus | component.menubar.item.background-focus-2color.status.dangervar(--menubar-item-background-focus-2) | Lightred.light.600:#C42B2BDarkred.dark.600:#F28B8B |
| Label focus 2 Changes with theme destructive, on focus | component.menubar.item.label-focus-2color.status.dangervar(--menubar-item-label-focus-2) | Lightred.light.600:#C42B2BDarkred.dark.600:#F28B8B |
| Icon size | component.menubar.item.icon-sizesize.iconvar(--menubar-item-icon-size) | size.20:1.25rem |
| Label 2 Changes with theme | component.menubar.item.label-2color.text.mutedvar(--menubar-item-label-2) | Lighttaupe.light.600:#6B544ADarktaupe.dark.400:#B5988A |
| Checkbox | ||
| Item gap | component.menubar.checkbox.item.gapspace.gap.defaultvar(--menubar-checkbox-item-gap) | space.16:1rem |
| Item radius | component.menubar.checkbox.item.radiusradius.badgevar(--menubar-checkbox-item-radius) | radius.999:9999px |
| Item padding y | component.menubar.checkbox.item.padding-ycomponent-spacing-map.x2var(--menubar-checkbox-item-padding-y) | space.8:0.5rem |
| Item padding right | component.menubar.checkbox.item.padding-rightcomponent-spacing-map.x2var(--menubar-checkbox-item-padding-right) | space.8:0.5rem |
| Item padding left | component.menubar.checkbox.item.padding-leftcomponent-spacing-map.x8var(--menubar-checkbox-item-padding-left) | space.64:4rem |
| Item font size | component.menubar.checkbox.item.font-sizetype.body.font-sizevar(--menubar-checkbox-item-font-size) | font.size.17:1.0625rem |
| Item background focus Changes with theme on focus | component.menubar.checkbox.item.background-focuscolor.surface.sunkenvar(--menubar-checkbox-item-background-focus) | Lighttaupe.light.100:#FCEFE6Darktaupe.dark.100:#33241F |
| Item label focus Changes with theme on focus | component.menubar.checkbox.item.label-focuscolor.text.primaryvar(--menubar-checkbox-item-label-focus) | Lighttaupe.light.900:#1F1411Darktaupe.dark.900:#FFF8F3 |
| Item disabled opacity disabled when disabled | component.menubar.checkbox.item.disabled-opacity-disabledopacity.disabledvar(--menubar-checkbox-item-disabled-opacity-disabled) | opacity.40:0.4 |
| Item icon size | component.menubar.checkbox.item.icon-sizesize.iconvar(--menubar-checkbox-item-icon-size) | size.20:1.25rem |
| Radio | ||
| Item gap | component.menubar.radio.item.gapspace.gap.defaultvar(--menubar-radio-item-gap) | space.16:1rem |
| Item radius | component.menubar.radio.item.radiusradius.badgevar(--menubar-radio-item-radius) | radius.999:9999px |
| Item padding y | component.menubar.radio.item.padding-ycomponent-spacing-map.x2var(--menubar-radio-item-padding-y) | space.8:0.5rem |
| Item padding right | component.menubar.radio.item.padding-rightcomponent-spacing-map.x2var(--menubar-radio-item-padding-right) | space.8:0.5rem |
| Item padding left | component.menubar.radio.item.padding-leftcomponent-spacing-map.x8var(--menubar-radio-item-padding-left) | space.64:4rem |
| Item font size | component.menubar.radio.item.font-sizetype.body.font-sizevar(--menubar-radio-item-font-size) | font.size.17:1.0625rem |
| Item background focus Changes with theme on focus | component.menubar.radio.item.background-focuscolor.surface.sunkenvar(--menubar-radio-item-background-focus) | Lighttaupe.light.100:#FCEFE6Darktaupe.dark.100:#33241F |
| Item label focus Changes with theme on focus | component.menubar.radio.item.label-focuscolor.text.primaryvar(--menubar-radio-item-label-focus) | Lighttaupe.light.900:#1F1411Darktaupe.dark.900:#FFF8F3 |
| Item disabled opacity disabled when disabled | component.menubar.radio.item.disabled-opacity-disabledopacity.disabledvar(--menubar-radio-item-disabled-opacity-disabled) | opacity.40:0.4 |
| Item icon size | component.menubar.radio.item.icon-sizesize.iconvar(--menubar-radio-item-icon-size) | size.20:1.25rem |
| Text | ||
| Padding, left and right | component.menubar.label.padding-xcomponent-spacing-map.x2var(--menubar-label-padding-x) | space.8:0.5rem |
| Padding, top and bottom | component.menubar.label.padding-ycomponent-spacing-map.x2var(--menubar-label-padding-y) | space.8:0.5rem |
| Text size | component.menubar.label.font-sizetype.body.font-sizevar(--menubar-label-font-size) | font.size.17:1.0625rem |
| Weight | component.menubar.label.font-weighttype.label.font-weightvar(--menubar-label-font-weight) | font.weight.700:700 |
| Padding left | component.menubar.label.padding-leftcomponent-spacing-map.x8var(--menubar-label-padding-left) | space.64:4rem |
| Separator | ||
| Fill Changes with theme | component.menubar.separator.backgroundcolor.border.defaultvar(--menubar-separator-background) | Lighttaupe.light.200:#F2DCCFDarktaupe.dark.100:#33241F |
| Shortcut | ||
| Text size | component.menubar.shortcut.font-sizetype.caption.font-sizevar(--menubar-shortcut-font-size) | font.size.14:0.875rem |
| Text Changes with theme | component.menubar.shortcut.labelcolor.text.mutedvar(--menubar-shortcut-label) | Lighttaupe.light.600:#6B544ADarktaupe.dark.400:#B5988A |
| Sub | ||
| Trigger radius | component.menubar.sub.trigger.radiusradius.badgevar(--menubar-sub-trigger-radius) | radius.999:9999px |
| Trigger padding x | component.menubar.sub.trigger.padding-xcomponent-spacing-map.x2var(--menubar-sub-trigger-padding-x) | space.8:0.5rem |
| Trigger padding y | component.menubar.sub.trigger.padding-ycomponent-spacing-map.x2var(--menubar-sub-trigger-padding-y) | space.8:0.5rem |
| Trigger font size | component.menubar.sub.trigger.font-sizetype.body.font-sizevar(--menubar-sub-trigger-font-size) | font.size.17:1.0625rem |
| Trigger background focus Changes with theme on focus | component.menubar.sub.trigger.background-focuscolor.surface.sunkenvar(--menubar-sub-trigger-background-focus) | Lighttaupe.light.100:#FCEFE6Darktaupe.dark.100:#33241F |
| Trigger label focus Changes with theme on focus | component.menubar.sub.trigger.label-focuscolor.text.primaryvar(--menubar-sub-trigger-label-focus) | Lighttaupe.light.900:#1F1411Darktaupe.dark.900:#FFF8F3 |
| Trigger padding left | component.menubar.sub.trigger.padding-leftcomponent-spacing-map.x8var(--menubar-sub-trigger-padding-left) | space.64:4rem |
| Trigger background open Changes with theme when open | component.menubar.sub.trigger.background-opencolor.surface.sunkenvar(--menubar-sub-trigger-background-open) | Lighttaupe.light.100:#FCEFE6Darktaupe.dark.100:#33241F |
| Trigger label open Changes with theme when open | component.menubar.sub.trigger.label-opencolor.text.primaryvar(--menubar-sub-trigger-label-open) | Lighttaupe.light.900:#1F1411Darktaupe.dark.900:#FFF8F3 |
| Content radius | component.menubar.sub.content.radiusradius.controlvar(--menubar-sub-content-radius) | radius.999:9999px |
| Content background Changes with theme | component.menubar.sub.content.backgroundcolor.surface.raisedvar(--menubar-sub-content-background) | Lighttaupe.light.0:#FFFFFFDarktaupe.dark.100:#33241F |
| Content padding | component.menubar.sub.content.paddingcomponent-spacing-map.x1var(--menubar-sub-content-padding) | space.4:0.25rem |
| Content label Changes with theme | component.menubar.sub.content.labelcolor.text.primaryvar(--menubar-sub-content-label) | Lighttaupe.light.900:#1F1411Darktaupe.dark.900:#FFF8F3 |
| Content shadow Changes with theme | component.menubar.sub.content.shadowelevation.overlayvar(--menubar-sub-content-shadow) | Lightshadow.overlay:0px 24px 48px 0px #1F141133Darkshadow.overlay-dark:0px 24px 48px 0px #00000099 |
| From the system | ||
| Edge Changes with theme | color.border.default straight from the system, through --border | Lighttaupe.light.200 · #F2DCCFDarktaupe.dark.100 · #33241F |