Navigation
Menu Button
A button that opens a menu of commands, with the menu keyboard contract rather than a listbox's.
A button that opens a menu. Use it for a list of commands — a profile menu, a row’s actions — where choosing a row does something.
Preview
Section titled “Preview”<nana-menu-button label="Account">
<nana-menu-item value="settings">Settings</nana-menu-item>
<nana-menu-item value="billing">Billing</nana-menu-item>
<nana-menu-item value="signout">Sign out</nana-menu-item>
</nana-menu-button> Menu or dropdown?
Section titled “Menu or dropdown?”They look alike and behave differently, and picking the wrong one shows up as surprising keyboard behaviour rather than anything visible.
nana-menu-button | nana-dropdown | |
|---|---|---|
| Pattern | menu | listbox |
| Children | nana-menu-item | nana-option |
| Choosing a row | runs a command | selects a value and keeps it |
| Tab | closes it and moves on | closes it and moves on |
| Keeps a selection | no | yes |
A SACCO or account switcher picks a value, so it is a dropdown. A profile menu runs commands, so it is a menu button.
In both, Tab leaves rather than cycling inside — that is the pattern for both, and neither traps focus. Move between rows with the arrow keys.
Installation
Section titled “Installation”npm install @nana-tec/ui-componentsimport "@nana-tec/ui-components/menu-button";A custom trigger
Section titled “A custom trigger”Slot trigger to replace the label entirely — an avatar, an icon button,
anything. The slotted content sits inside the real button, so it keeps the
popup semantics.
<nana-menu-button>
<span slot="trigger">⋯</span>
<nana-menu-item value="rename">Rename</nana-menu-item>
<nana-menu-item value="delete">Delete</nana-menu-item>
</nana-menu-button> Naming the trigger
Section titled “Naming the trigger”A trigger that shows only an avatar or an icon has no accessible name, and
neither does one whose label is hidden at narrow widths. aria-label reaches
the real button inside:
<nana-menu-button aria-label="Switch account">
<span slot="trigger">AB</span>
<nana-menu-item value="one">Nairobi Sacco</nana-menu-item>
<nana-menu-item value="two">Mombasa Sacco</nana-menu-item>
</nana-menu-button> Without a label, an aria-label or trigger text, the component warns in the
console rather than shipping an unnamed control.
Keyboard
Section titled “Keyboard”| Key | Result |
|---|---|
| Enter / Space / ↓ | Opens onto the first row |
| ↑ | Opens onto the last row |
| ↑ / ↓ | Moves between rows, wrapping at the ends |
| Home / End | Jumps to the first or last row |
| Esc | Closes it and returns focus to the button |
| Tab | Closes it and carries on to whatever follows |
Disabled rows are skipped.
Properties
| Property | Attribute | Type | Default | Description |
|---|---|---|---|---|
ariaLabel | aria-label | string | null | null | Names the trigger when its content cannot. A trigger showing only an avatar or an icon — or one whose label is hidden at narrow widths — has no accessible name without this. |
disabled | disabled | boolean | false | |
label | label | string | '' | Text on the trigger when no trigger slot is given. |
open | open | boolean | false | |
placement | placement | 'start' | 'end' | 'start' | Side the panel sits on when there is room. |
Events
| Event | Description |
|---|---|
nana-open | After the menu opens |
nana-close | After the menu closes |
nana-select | Bubbled from a chosen item (detail.value) |
Slots
| Slot | Description |
|---|---|
trigger | Custom trigger content (falls back to the label text) |
(default) | nana-menu-item / nana-menu-label / <hr> children |
CSS parts
| Part | Description |
|---|---|
::part(trigger) | The button |
::part(panel) | The floating menu panel |
CSS custom properties
| Property | Description |
|---|---|
--nana-menu-button-panel-min-width | Narrowest the panel may be |
--nana-menu-button-z | Stacking order for the panel |
Events
Section titled “Events”| Event | Type | Description |
|---|---|---|
nana-open | CustomEvent | The menu opened. |
nana-close | CustomEvent | The menu closed. |
nana-select | CustomEvent | Bubbled from a chosen row; detail.value. |
Accessibility
Section titled “Accessibility”The trigger carries aria-haspopup="menu" and aria-expanded, and the panel is
a labelled menu. Focus moves onto a real row rather than being tracked with
aria-activedescendant, which is what separates a menu from a listbox.