Menubar
A desktop-app-style top menu bar (File / Edit / View). Click or hover expands submenus (cascading popups), with arrow key support, Alt access keys and a focus trap.
Multi-group radio (independent checkmarks per group)
The value of a type: "group" item acts as a group id. Leaves inside the same group record their selection independently; when value is a JSON object string ({"group-id":"selected"}), groups don't interfere — both "Mode" and "Theme" can show a checkmark at once.
Multi-group radio
Action items (kind: "action")
Leaves with kind: "action" render as plain actions (menuitem): no checkmark, clicks do not write back value, and only oas-select is dispatched (detail.kind === "action"). Fits "Open / Save / About" style items.
Action items (kind: action)
Shortcuts (shortcut)
The shortcut field (e.g. "Ctrl+N"): renders a key hint on the right, and auto-binds a document-level keydown — pressing the combo selects that item (preventDefault blocks the browser default).
Shortcuts
Basic usage
Basic usage
Disabled items and groups
Submenus support disabled, type: "divider" separators and type: "group" group titles.
Disabled items and groups
Controlled selection
The value attribute is controlled (it is in observedAttributes): an external setAttribute('value', ...) takes effect immediately and syncs the selected item (check/highlight) to the corresponding leaf item; internal clicks also write back to value (uncontrolled channel), and the host can listen to oas-select to take over.
Controlled selection (value attribute)
Checkbox items and keep-open (checkbox + close-on-select)
Leaves with kind: "checkbox" toggle a multi-select checked set (value is a JSON array); toggling a checkbox does not close the submenu (continuous toggling). close-on-select="false" keeps the submenu open even after radio/action selections.
Checkbox + close-on-select
Controlled open (open)
The open attribute holds the value of the currently open top-level menu (open="" closes all). Controlled attribute: an external setAttribute('open', ...) opens/switches/closes immediately; internal changes write open back and dispatch oas-open-change (detail: { value, open }) for the host to take over.
Controlled open (open attribute)
Trigger mode and arrow-key wrap (trigger / loop)
trigger="click" (default): a top-level menu opens on click first; once one is open, hovering another top-level item switches to it (desktop convention). trigger="hover" opens directly on hover. loop="false" disables wrap-around at the edges.
Hover opens directly (trigger)
No wrap-around (loop)
Disabled bar (disabled)
disabled disables the whole bar: top-level/sub-item clicks, keyboard navigation, shortcut hotkeys and Alt access keys are all blocked.
Disabled bar (disabled)
Popup positioning and arrow (side / align / offset / show-arrow)
side controls the first-level popup side (default bottom), align its alignment (default start), offset the gap to the trigger (px); show-arrow draws a visual arrow pointing at the trigger.
Popup positioning + arrow (side / align / offset / show-arrow)
Vertical orientation (orientation)
orientation="vertical": the bar stacks vertically, first-level popups default to the right; ↑/↓ move between top-level items, → opens a submenu.
Vertical (orientation)
Mobile hamburger folding (breakpoint)
breakpoint="600": when the viewport is ≤ 600px wide the bar folds into a hamburger button + popup menu (narrow-width folding); widen the window to restore the full bar.
Mobile hamburger (breakpoint)
Icons (icon)
Both top-level items and sub-items accept an icon field (icon-set name); icons follow the text color.
Icons (icon)
API
Attributes
| Attribute | Description | Type | Default |
|---|---|---|---|
align | First-level popup alignment: start (default) / center / end; with side top/bottom it aligns on the horizontal axis, with left/right on the vertical axis | string | — |
breakpoint | Mobile breakpoint (px, e.g. 600): when the viewport width is ≤ the breakpoint the bar collapses into a hamburger button + popup menu (narrow-width folding) | string | — |
close-on-select | Whether selecting a leaf closes the open submenu, default true (desktop menubar convention); close-on-select="false" keeps it open (multi-select scenario); kind:"checkbox" items never close on toggle | string | — |
disabled | Disable the whole bar: top-level/sub-item clicks, keyboard navigation, shortcut hotkeys and Alt access keys are all blocked; visually desaturated | boolean | — |
items | Top-level menu items JSON (with submenu children) | string | [] |
loop | Arrow-key wrap-around toggle, default true (loops at edges); explicit loop="false" stops at the edges | string | — |
offset | Gap between the first-level popup and its trigger (px, default 4) | string | — |
open | Value of the currently open top-level menu (open="" closes all). Controlled attribute (in observedAttributes): an external setAttribute('open', ...) opens/switches/closes immediately; internal click/hover/keyboard changes write it back and dispatch oas-open-change, letting the host take over | string | — |
orientation | Arrangement direction: horizontal (default) / vertical (bar stacks vertically, first-level popups default to the right, arrow keys move top-level items up/down) | — | — |
show-arrow | Show a visual arrow on the popup pointing at the trigger | — | — |
side | First-level popup side: bottom (default horizontal) / top / left / right (default vertical); cascading submenus are unaffected | string | — |
trigger | Top-level menu trigger: click (default, click to open first, then hover switches — desktop convention) / hover (hover opens directly) | — | — |
value | Selected value. As a plain string it is a single global selection (no-group scenarios, backward compatible); as a JSON object string (e.g. {"mode":"preview","theme":"dark"}) selections are recorded per group id — the value of a type:"group" item acts as the group id; as a JSON array string (e.g. ["grid","wrap"]) it is the checkbox checked-set (kind:"checkbox" items, multi-select) | string | — |
Events
| Event | Description |
|---|---|
oas-open-change | The open top-level menu changed, detail: { value, open } (value = currently open top-level menu value, open = whether anything is open). Fired both on controlled setAttribute('open') and internal click/hover/keyboard changes (not on the first frame) |
oas-select | An item was selected, detail: { value, kind?, checked? }. kind only appears for action items (kind: "action"); checkbox items carry checked (new checked state); radio items omit detail.kind |
Event detail note: the
detailofoas-selectis a component-internal object (value/kind) — not a nativeEvent, so you can'tpreventDefault()on it or read a nativeevent.targetfrom it. To reach the native event, use the outer parameter of your listener (e.g. inaddEventListener('oas-select', (e) => ...),eis aCustomEventande.detailis the component data).
MenubarItem fields (inherits MenuItem):
| Field | Description | Type |
|---|---|---|
label | Menu text | string |
value | Selection value (declared in the items JSON; after render the host tag carries a data-value lowercased attribute for internal lookup — hosts shouldn't rely on it as public API) | string |
kind | Leaf semantics: radio (default, checkable, participates in value) / action (action item, no checkmark, doesn't write back value on click) | string |
shortcut | Shortcut hint (e.g. "Ctrl+N"); renders as a right-side kbd and auto-binds a document-level keydown (selects the item on match, preventDefault) | string |
accessKey | Alt access key (single character); defaults to the first ASCII letter of label | string |
disabled | Disabled | boolean |
children | Submenu items (nested recursively, cascading to the right) | MenubarItem[] |
Keyboard: at top level ←/→ switch, ↓/Enter opens the submenu, Esc closes; inside a submenu ↑/↓ move, → enters a cascading submenu, ← returns to the parent; Home/End jump. Pressing Alt alone focuses the menu bar, Alt + access key opens the matching top-level menu. While a submenu is open, Tab cycles among its items (focus trap); roving tabindex keeps only the current top-level item tab-reachable.