Skip to content

Menu ​

A standalone menu list with selection state and keyboard navigation.

Basic usage ​

Basic usage

Default selection ​

Default selection (value echo)

Disabled items ​

Disabled items

Nested submenu ​

Menu items with children show an expand arrow (›); clicking or hovering expands the submenu, which is rendered indented; press ArrowRight to enter and ArrowLeft to go back.

Nested submenu

Nothing selected

Horizontal navigation ​

With mode="horizontal" the items are laid out in a row as a top navigation bar; first-level submenus pop down while second-level and deeper submenus still pop to the right.

Horizontal navigation (top bar style)

Nothing selected

Collapsed state ​

collapsed (vertical / inline; not applicable to horizontal) narrows the menu to show only icons; in vertical mode hovering or clicking an icon item pops its submenu out to the right (still a full menu), while inline mode does not fly out — submenus still expand in place (click-to-expand, no hover expansion).

Collapsed (icons only)

Nothing selected

Groups ​

Menu items with type: "group" render as a section with a group title (small text, secondary color, not clickable); the group's children are laid out flat on the same level and may mix in submenus and dividers.

Groups

With icons ​

icon uses icon names from @oas-ui/icons (built-in icon set) and renders an inline SVG to the left of the text.

With icons

Icon color (iconColor) ​

The iconColor field fixes the icon color (overriding the selected/disabled default); any CSS color or token works, and it defaults to currentColor following the text color. The declarative child channel uses the icon-color attribute.

Icon color (iconColor / icon-color)

DownloadDeleteNo icon-color

Divider ​

type: "divider" renders a thin divider line that is not clickable and not part of keyboard navigation.

Divider

Declarative child channel ​

Besides the items JSON, you can write items declaratively with <oas-menu-item> / <oas-menu-group> / <oas-menu-divider> (the items attribute wins when explicitly set; otherwise child elements are parsed and converge to the same render path). The default slot text is the label; attributes map to the items fields: value / disabled / loading / icon / kind / danger / href / target / rel. Nesting child elements directly inside <oas-menu-item> recursively becomes a submenu; <oas-menu-group> uses its label attribute as the group title (value can serve as a radio group id) and flattens its children to the same level. Child additions/removals, attribute and text changes re-render automatically (MutationObserver).

Declarative child channel (group / divider / nesting / checkbox / danger / href)

HomeComponent docsEdit CopyCutShow gridlinesWord wrapDeleteNothing selected

Dynamic add/remove (MutationObserver auto-refresh)

Append an itemHomeSettings

Leading media (slot="leading") ​

Menu items support a leading media slot: put a <template slot="leading"> (or a direct child with slot="leading") inside <oas-menu-item>; the content renders before the label and takes precedence over the icon attribute (when both are given the icon is not rendered); in the loading state the spinner replaces the leading media, and in the collapsed state the media converges like icons (kept visible with zeroed spacing — hiding it would leave a hoverable blank item). Suited to avatars, color chips, and any rich leading content (items JSON does not support it — declarative children only).

Leading avatars (avatar example)

Lin XiaoyuChen YiningZhao QimingSign out

Dark menu ​

theme="dark" applies dark tokens locally (dark background + light text) to the menu, independent of the global theme; when unset, it follows the global theme.

Dark menu

Selection event ​

Selection event

Nothing selected

Multi-select (checkbox) ​

Leaf items with kind: "checkbox" render as square checkboxes (role="menuitemcheckbox", distinct from the radio ✓); the checked set is written to value as a JSON array, and after a click oas-select carries checked in its detail (the state after this click).

Multi-select (checkbox)

Nothing checked

Destructive items ​

danger: true applies red semantics (--oas-color-danger) for destructive actions such as delete or sign out; the red background deepens on hover / keyboard highlight.

Destructive items (danger)

Nothing selected

href renders the item as an <a> (anchor semantics: middle-click / right-click in a new window, SEO friendly); target / rel are passed through as-is. Clicking still fires oas-select and writes the selected state. The example links use target="_blank" so they open in a new tab and you stay on this page.

Link items (href)

Nothing selected

Long menu scrolling ​

max-height caps the visible height of the menu (a plain number is treated as px); overflowing items scroll inside the menu — handy for long lists.

Long menu scrolling (max-height)

Typeahead ​

With the menu focused, typing a character jumps to the item whose label matches (character buffer with a 500ms idle reset; prefix match first, falls back to substring). The example labels include English so you can type: press c to jump to Copy, then u (combined cu) to jump to Cut.

Typeahead

Menu focused — just type (e.g. c → Copy, cu → Cut)

Inline sidebar navigation ​

With mode="inline" submenus expand in place (no flyout) — the mainstream sidebar navigation form; expanding / collapsing animates the height, and multi-level nesting is supported.

Inline expand

Controlled expansion ​

expanded (JSON array) is a controlled attribute: setting / updating it from outside specifies which submenus are open. Every expand / collapse fires oas-expand-change (detail: { expanded, value, isExpanded }); in the controlled pattern the host writes the state back to expanded.

Controlled expanded

Expand "Workspace"Expand "Messages"Collapse allNot touched yet

Keep open on select ​

Flyout modes (vertical / horizontal) collapse expanded submenus after a leaf is selected by default (expansion is temporary); close-on-select="false" keeps them open — handy for picking several items in a row. mode="inline" side navigation keeps submenus open by default (users need to see their section); close-on-select="true" changes that to collapse. kind="checkbox" items never collapse on toggle. close-on-select is a boolean attribute: presence means true (including an empty value such as close-on-select=""); only an explicit "false" disables it — the mode-based defaults above apply only when the attribute is absent.

Keep open on select (close-on-select)

vertical + close-on-select="false": the submenu stays open after picking a leaf

Nothing selected

inline + close-on-select="true": the parent collapses after picking a leaf

Nothing selected

Accordion ​

accordion (with mode="inline") makes sibling submenus mutually exclusive: expanding one automatically collapses the other open siblings.

Accordion (inline + accordion)

Horizontal overflow ​

With mode="horizontal", when the container is too narrow the overflowing items are automatically folded into a trailing "···" submenu — the nav bar never wraps or truncates.

Horizontal overflow

Hover to Expand Submenus ​

open-on-hover gives parent items in vertical / inline modes hover expansion: hovering for ~150ms opens the submenu, moving away closes it after ~300ms (moving back within the grace period cancels the close); the click path is unchanged (items still toggle on click). The mode="horizontal" top nav and the collapsed flyout already open instantly on hover and are unaffected by this attribute.

open-on-hover (vertical, delayed hover expansion)

vertical: hover "Edit" for ~150ms to open; it closes ~300ms after the pointer leaves

inline: hover also expands (multiple branches may stay open); clicking still toggles

Whole-menu disabled ​

disabled disables the entire menu: click / hover / keyboard are all intercepted (href items also get their native navigation blocked), the host text switches to the disabled color (no opacity overlay) and is synced with aria-disabled; removing the attribute restores interaction.

Whole-menu disabled

Pure action menu (selectable=false) ​

selectable="false" turns off selection semantics for the whole menu: every leaf item renders as an action item (menuitem, no check mark, no aria-checked), clicking only emits oas-select and never writes back value — for pure command menus ("click and go"; equivalent to writing every leaf as kind: "action").

Pure action menu (no check marks, value not written back)

Keep submenus open on select (persistent) ​

persistent keeps flyout submenus open after a selection (the positive switch of the close-on-select family; when explicit it wins over close-on-select): for continuous-pick scenarios where the menu should stay where it is; value is still written back.

persistent: submenu stays open after selecting

Searchable (searchable) ​

searchable renders a filter input at the top of the menu and filters visible items live (works in both floating and inline modes): when a nested child matches, its ancestors are kept and the matching path is auto-expanded; when nothing matches, an i18n empty message is shown. Escape clears the search, ArrowDown moves focus into the menu.

Searchable (floating + inline)

Floating: type "Win" to filter down to "Window layout"

Nothing selected

Inline: type "Stats" to filter in place and expand the matching path

Shortcut hints (shortcut) ​

The menu item shortcut field (items JSON) or the <oas-menu-item shortcut="…"> attribute renders a kbd hint at the trailing edge, matching the menubar shortcut visual contract.

Shortcut hints (shortcut)

UndoRedoPaste

API ​

oas-menu ​

Attributes ​

AttributeDescriptionTypeDefault
accordionAccordion mutual exclusion (inline mode: only one sibling submenu open at a time)boolean—
close-on-selectWhether expanded submenus collapse after a leaf item is selected. Defaults by mode: inline side navigation keeps them open, flyout modes collapse; checkbox items never collapse on togglestring—
collapsedCollapsed state (vertical / inline; not applicable to horizontal): icons only, submenus pop to the rightboolean—
disabledDisables the whole menu: click/hover/keyboard intercepted, dimmed with aria-disabledboolean—
expandedControlled expanded set (JSON array string; which submenus are open in inline mode); internally managed when uncontrolledstring—
itemsMenu items JSON (supports disabled / loading, icon, children submenus)MenuItem[] | null[]
max-heightMax height of a long menu; scrolls internally beyond it (number gets px appended)string—
modeLayout mode: vertical (default) menu / horizontal top bar / inline side navigation (submenus expand in place with a height transition)——
open-on-hoverHover-opened submenus in vertical/inline modes (~150ms open / ~300ms close delay); clicks unchanged; horizontal and collapsed flyout unaffectedboolean—
persistentKeep flyout submenus open after selection (wins over close-on-select)string—
searchableRenders a filter input at the top of the menu and filters visible items live (matching ancestors are kept and auto-expanded; Esc clears)boolean—
selectableWith "false", pure action menu: no check marks, clicks never write back value (detail kind=action)stringtrue
themeLocal theme: dark uses dark tokens (independent of the global theme)——
valueCurrent selected value. Plain string means global single-select (no group, legacy-compatible); JSON object string (e.g. {"sort":"name","view":"list"}) scopes per group id — the value of a type:"group" item is the group id, picking inside a group only updates that groupstring—

Events ​

EventDescription
oas-expand-changeSubmenu expand state changed, detail: { expanded: string[], value, isExpanded } (fired both controlled and uncontrolled)
oas-selectSelect an item, detail: { value, kind? }. kind only appears for action items (kind: "action") as "action"; radio items omit detail.kind

CSS Variables ​

CSS VariableDefault
--oas-menu-max-heightnone

oas-menu-item ​

Attributes ​

AttributeDescriptionTypeDefault
dangerDestructive item: danger color semantics (delete/logout operations)——
disabledDisable this item——
hrefLink URL: with href the item renders as a native <a> (real navigation + still fires oas-select)——
iconLeading icon (@oas-ui/icons registry icon name)——
icon-colorIcon color: fixes the icon to this color (overrides the selected/disabled default); defaults to currentColor following the text color——
kindLeaf semantics: radio (default, selectable) / action (no checked state, does not write back value) / checkbox (multi-select, value is the checked-set array)——
loadingLoading state: renders a spinner and blocks clicks; restored by data updates——
relLink rel (with href)——
shortcutShortcut hint rendered as a trailing kbd (aligned with the menubar shortcut contract)——
targetLink target (with href)——
valueSelection value (data-carrier field of the declarative child channel)——

Slots ​

NameDescription
defaultMenu item label content (default slot text); direct child <oas-menu-item>/<oas-menu-group>/<oas-menu-divider> elements recursively become the submenu children
template[slot="leading"]Leading media template (or a direct child with slot="leading"): avatars/color chips/any rich leading content, rendered before the label and taking precedence over the icon attribute; replaced by the spinner in the loading state; declarative child channel only (not supported by the items JSON)

oas-menu-group ​

Attributes ​

AttributeDescriptionTypeDefault
labelGroup title (small secondary text, not clickable)——
valueRadio group id (picking inside the group only updates that group's selected value)——

Slots ​

NameDescription
defaultGroup items: child <oas-menu-item>/<oas-menu-group>/<oas-menu-divider> elements flatten to the same level

oas-menu-divider ​

Slots ​

NameDescription
defaultDivider data carrier (no attributes; the host parses it as type: "divider")

MenuItem fields:

FieldDescriptionType
labelMenu item textstring
valueSelection valuestring
typeItem type: item (default) / group (group title) / dividerstring
kindLeaf semantics: radio (default, checkable) / action (action item, no checkmark, doesn't write back value on click)string
iconIcon name (a key of @oas-ui/icons built-in icon set)string
iconColorIcon color (optional): fixes the icon to this color, overriding the selected/disabled default; defaults to currentColor following the text colorstring
disabledDisables the itemboolean
childrenSubmenu items array with the same shape as the parent (nested recursively)MenuItem[]

children is an optional submenu items array; items with children expand their submenu on click/hover, and the selected state only lands on leaf items. group children are laid out flat on the same level; group titles are not clickable and skipped in keyboard navigation; divider items are not clickable and skipped in keyboard navigation.

Keyboard navigation: arrow keys move (auto-skipping group titles and dividers), Enter selects (items with submenus enter via Enter/ArrowRight), Home / End jump, ArrowLeft returns to the parent; role="menu" + menuitemradio (submenu parents are menuitem), the selected item shows a check mark.

Released under the MIT OR Apache-2.0 License.