media-menu
A composable menu component for settings, option selection, and actions
Import
import { Menu } from '@videojs/react';import '@videojs/html/ui/menu';Anatomy
A root menu owns one positioned Popup. Nested Content elements share that Popup with the root Content.
<Menu.Root>
<Menu.Trigger />
<Menu.Popup>
<Menu.Content>
{/* Parent menu item that opens a submenu */}
<Menu.Root>
<Menu.Trigger />
<Menu.Content>
<Menu.Item>Back</Menu.Item>
<Menu.RadioGroup>
<Menu.GroupLabel />
<Menu.RadioItem>
<Menu.ItemIndicator />
</Menu.RadioItem>
</Menu.RadioGroup>
</Menu.Content>
</Menu.Root>
{/* Other parent menu items */}
<Menu.Group>
<Menu.GroupLabel />
<Menu.CheckboxItem>
<Menu.ItemIndicator />
</Menu.CheckboxItem>
</Menu.Group>
<Menu.Separator />
<Menu.Item />
</Menu.Content>
</Menu.Popup>
</Menu.Root><button type="button" commandfor="settings-menu">Settings</button>
<media-menu id="settings-menu">
<media-menu-content>
<!-- Parent menu item that opens a submenu -->
<media-menu-item commandfor="submenu">
Open submenu
</media-menu-item>
<!-- Other parent menu items -->
<media-menu-group>
<media-menu-group-label></media-menu-group-label>
<media-menu-checkbox-item>
<media-menu-item-indicator></media-menu-item-indicator>
</media-menu-checkbox-item>
</media-menu-group>
<media-menu-separator></media-menu-separator>
<media-menu-item></media-menu-item>
</media-menu-content>
<!-- Sibling Content opened by the parent item -->
<media-menu-content id="submenu">
<media-menu-item>Back</media-menu-item>
<media-menu-radio-group>
<media-menu-group-label></media-menu-group-label>
<media-menu-radio-item>
<media-menu-item-indicator></media-menu-item-indicator>
</media-menu-radio-item>
</media-menu-radio-group>
</media-menu-content>
</media-menu>Behavior
Menus open from a trigger and close when you select an item, click outside, move focus away, or press Escape. Root menus use side and align as their preferred placement. When the preferred side overflows the positioning boundary, the menu uses the opposite side if it has more space.
Root menus inside a Container join its popup group. Opening one closes any other root menu or popover that is open in the same container. Submenus remain part of their root menu instead of registering separately.
In React, create a submenu by nesting another Menu.Root in the parent Menu.Content; its Menu.Trigger behaves as a parent item and its Menu.Content becomes the active Content. In HTML, add another <media-menu-content> as a sibling, give it an id, and point the parent <media-menu-item> at it with commandfor.
Media option groups can render the current selection beside a submenu trigger. See PlaybackRateRadioGroup, QualityRadioGroup, AudioTrackRadioGroup, and CaptionsRadioGroup.
Styling
Use data attributes to style open state, highlighted items, selected radio items, and submenu views:
data-highlighted identifies the current menu item. Its value is "pointer" when pointer movement caused the highlight and an empty string for other highlights, including keyboard navigation and type-ahead search. Use [data-highlighted] to match any highlighted item or [data-highlighted=""] to match highlights that were not caused by pointer movement.
The root Menu.Popup or <media-menu> receives data-open, data-side, and data-align. Each Content receives menu state such as data-open and data-submenu; a Content with an open logical child receives data-child-open.
Every navigable item receives data-item. Use [data-item] when one rule should target regular, radio, checkbox, and submenu-trigger items together.
.menu-popup[data-open] {
opacity: 1;
}
.menu-content[data-child-open] {
translate: -100% 0;
}
.menu-item[data-highlighted] {
background: rgba(255, 255, 255, 0.16);
transition: background-color 100ms ease-in-out;
}
.menu-item[data-highlighted=""] {
transition-duration: 0ms;
}
[role="menuitemradio"][aria-checked="true"] {
font-weight: 600;
}media-menu[data-open] {
opacity: 1;
}
media-menu-content[data-child-open] {
translate: -100% 0;
}
media-menu-item[data-highlighted] {
background: rgba(255, 255, 255, 0.16);
transition: background-color 100ms ease-in-out;
}
media-menu-item[data-highlighted=""] {
transition-duration: 0ms;
}
media-menu-radio-item[aria-checked="true"] {
font-weight: 600;
}Accessibility
Menu content renders with role="menu". Items use menuitem, menuitemradio, or menuitemcheckbox roles. Radio and checkbox items reflect selection with aria-checked.
Keyboard controls:
- Enter / Space: Select the highlighted item.
- Arrow Up / Arrow Down: Move between items.
- Arrow Right: Open a submenu.
- Arrow Left: Return to the parent menu.
- Escape: Close the root menu or return from a submenu.
Use Menu.GroupLabel or <media-menu-group-label> inside grouped choices so the group receives an accessible label.
Examples
Basic usage
import {
Container,
createPlayer,
Menu,
useAudioTrackOptions,
useCaptionsOptions,
usePlaybackRateOptions,
useQualityOptions,
} from '@videojs/react';
import { HlsJsVideo } from '@videojs/react/media/hlsjs-video';
import { videoFeatures } from '@videojs/react/video';
import type { ReactNode } from 'react';
const { Player } = createPlayer({ features: videoFeatures });
const src = 'https://stream.mux.com/s41JYeqIpBMBzE4OzxDyGR2yrp2hD1CQ6gJN9SlVGDQ.m3u8';
function SettingsMenu(): ReactNode {
const playbackRate = usePlaybackRateOptions();
const quality = useQualityOptions();
const audioTrack = useAudioTrackOptions();
const captions = useCaptionsOptions();
const hasPlaybackRate = playbackRate?.state.availability === 'available';
const hasQuality = quality?.state.availability === 'available';
const hasAudioTrack = audioTrack?.state.availability === 'available';
const hasCaptions = captions?.state.availability === 'available';
if (!hasPlaybackRate && !hasQuality && !hasAudioTrack && !hasCaptions) return null;
return (
<Menu.Root side="top" align="end">
<Menu.Trigger className="settings-trigger" aria-label="Settings" render={<button type="button" />}>
Settings
</Menu.Trigger>
<Menu.Popup className="menu">
<Menu.Content className="menu-content">
{hasQuality ? (
<Menu.Root>
<Menu.Trigger
className="menu-item"
render={(props) => (
<div {...props}>
<span>Quality</span>
<span className="menu-value">
{quality.selectedLabel}
<span aria-hidden="true">›</span>
</span>
</div>
)}
/>
<Menu.Content className="menu-panel">
<Menu.Item className="menu-back">
<span aria-hidden="true">‹</span>
Quality
</Menu.Item>
<Menu.RadioGroup
className="menu-group"
value={quality.value}
onValueChange={quality.setValue}
aria-label="Quality"
>
{quality.options.map((option) => (
<Menu.RadioItem
key={option.value}
value={option.value}
disabled={option.disabled}
className="menu-item"
>
<span>
{option.label}
{option.tier ? <sup className="menu-tier">{option.tier}</sup> : null}
</span>
{option.badge ? <span className="menu-badge">{option.badge}</span> : null}
<Menu.ItemIndicator
checked={option.value === quality.value}
forceMount
className="menu-indicator"
>
✓
</Menu.ItemIndicator>
</Menu.RadioItem>
))}
</Menu.RadioGroup>
</Menu.Content>
</Menu.Root>
) : null}
{hasAudioTrack ? (
<Menu.Root>
<Menu.Trigger
className="menu-item"
render={(props) => (
<div {...props}>
<span>Audio</span>
<span className="menu-value">
{audioTrack.selectedLabel}
<span aria-hidden="true">›</span>
</span>
</div>
)}
/>
<Menu.Content className="menu-panel">
<Menu.Item className="menu-back">
<span aria-hidden="true">‹</span>
Audio
</Menu.Item>
<Menu.RadioGroup
className="menu-group"
value={audioTrack.value}
onValueChange={audioTrack.setValue}
aria-label="Audio tracks"
>
{audioTrack.options.map((option) => (
<Menu.RadioItem
key={option.value}
value={option.value}
disabled={option.disabled}
className="menu-item"
>
<span>{option.label}</span>
<Menu.ItemIndicator
checked={option.value === audioTrack.value}
forceMount
className="menu-indicator"
>
✓
</Menu.ItemIndicator>
</Menu.RadioItem>
))}
</Menu.RadioGroup>
</Menu.Content>
</Menu.Root>
) : null}
{hasPlaybackRate ? (
<Menu.Root>
<Menu.Trigger
className="menu-item"
render={(props) => (
<div {...props}>
<span>Speed</span>
<span className="menu-value">
{playbackRate.selectedLabel}
<span aria-hidden="true">›</span>
</span>
</div>
)}
/>
<Menu.Content className="menu-panel">
<Menu.Item className="menu-back">
<span aria-hidden="true">‹</span>
Speed
</Menu.Item>
<Menu.RadioGroup
className="menu-group"
value={playbackRate.value}
onValueChange={playbackRate.setValue}
aria-label="Playback rate"
>
{playbackRate.options.map((option) => (
<Menu.RadioItem
key={option.value}
value={option.value}
disabled={option.disabled}
className="menu-item"
>
<span>{option.label}</span>
<Menu.ItemIndicator
checked={option.value === playbackRate.value}
forceMount
className="menu-indicator"
>
✓
</Menu.ItemIndicator>
</Menu.RadioItem>
))}
</Menu.RadioGroup>
</Menu.Content>
</Menu.Root>
) : null}
{hasCaptions ? (
<Menu.Root>
<Menu.Trigger
className="menu-item"
render={(props) => (
<div {...props}>
<span>Captions</span>
<span className="menu-value">
{captions.selectedLabel}
<span aria-hidden="true">›</span>
</span>
</div>
)}
/>
<Menu.Content className="menu-panel">
<Menu.Item className="menu-back">
<span aria-hidden="true">‹</span>
Captions
</Menu.Item>
<Menu.RadioGroup
className="menu-group"
value={captions.value}
onValueChange={captions.setValue}
aria-label="Captions"
>
{captions.options.map((option) => (
<Menu.RadioItem
key={option.value}
value={option.value}
disabled={option.disabled}
className="menu-item"
>
<span>{option.label}</span>
<Menu.ItemIndicator
checked={option.value === captions.value}
forceMount
className="menu-indicator"
>
✓
</Menu.ItemIndicator>
</Menu.RadioItem>
))}
</Menu.RadioGroup>
</Menu.Content>
</Menu.Root>
) : null}
<Menu.Item className="menu-item" onSelect={() => navigator.clipboard?.writeText(window.location.href)}>
Copy link
</Menu.Item>
</Menu.Content>
</Menu.Popup>
</Menu.Root>
);
}
export default function BasicUsage() {
return (
<Player>
<Container className="media-container">
<HlsJsVideo src={src} autoPlay crossOrigin="anonymous" muted playsInline loop>
<track kind="captions" src="/docs/demos/captions-button/captions.vtt" srcLang="en" label="English" />
<track kind="subtitles" src="/docs/demos/captions-button/captions.vtt" srcLang="es" label="Spanish" />
</HlsJsVideo>
<div className="menu-bar">
<SettingsMenu />
</div>
</Container>
</Player>
);
}
.media-container {
position: relative;
}
.media-container video {
width: 100%;
}
.menu-bar {
position: absolute;
right: 10px;
bottom: 10px;
}
.settings-trigger {
padding: 6px 16px;
color: black;
cursor: pointer;
background: rgba(255, 255, 255, 0.75);
border: 1px solid rgba(255, 255, 255, 0.35);
border-radius: 9999px;
backdrop-filter: blur(10px);
}
.menu {
--media-menu-side-offset: 8px;
--menu-transition-duration: 220ms;
position: relative;
box-sizing: border-box;
width: var(--media-menu-width);
min-width: 180px;
max-width: var(--media-menu-available-width, var(--media-popover-available-width, none));
height: var(--media-menu-height);
max-height: var(--media-menu-available-height, var(--media-popover-available-height, none));
padding: 6px;
margin: 0;
overflow: hidden;
overscroll-behavior: none;
font-size: 14px;
color: white;
background: rgba(0, 0, 0, 0.88);
border: 0;
border-radius: 8px;
backdrop-filter: blur(10px);
transition-timing-function: ease-in-out;
transition-duration: var(--menu-transition-duration);
transition-property: width, height, opacity, filter;
}
.menu-content,
.menu-panel {
position: absolute;
inset: 0;
display: grid;
gap: 2px;
padding: 6px;
overflow: auto;
overscroll-behavior: none;
outline: none;
translate: 0 0;
transition-timing-function: ease-in-out;
transition-duration: var(--menu-transition-duration);
transition-property: translate, filter;
}
.menu-content[data-child-open] {
filter: blur(8px);
translate: -100% 0;
}
.menu-panel[data-submenu] {
z-index: 1;
}
.menu-panel[data-submenu][data-starting-style],
.menu-panel[data-submenu][data-ending-style] {
overflow: hidden;
pointer-events: none;
filter: blur(8px);
translate: 100% 0;
}
.menu-item,
.menu-back {
display: flex;
align-items: center;
justify-content: space-between;
min-height: 32px;
padding: 0 10px;
font: inherit;
color: inherit;
cursor: pointer;
background: none;
border: 0;
border-radius: 6px;
}
.menu-item[data-highlighted],
.menu-back:hover {
background: rgba(255, 255, 255, 0.16);
}
.menu-back {
gap: 8px;
justify-content: flex-start;
}
.menu-value {
display: inline-flex;
gap: 8px;
align-items: center;
color: rgba(255, 255, 255, 0.72);
}
.menu-group {
display: grid;
gap: 2px;
}
.menu-tier {
margin-left: 2px;
font-size: 10px;
}
.menu-badge {
margin-left: auto;
color: rgba(255, 255, 255, 0.72);
}
.menu-back [aria-hidden],
[role="menuitemradio"] [aria-hidden],
.menu-item [aria-hidden] {
font-size: 18px;
line-height: 1;
color: rgba(255, 255, 255, 0.72);
}
.menu-indicator {
opacity: 0;
}
[role="menuitemradio"][aria-checked="true"] .menu-indicator {
opacity: 1;
}
<video-player class="video-player">
<media-container>
<hlsjs-video
class="video-media"
src="https://stream.mux.com/s41JYeqIpBMBzE4OzxDyGR2yrp2hD1CQ6gJN9SlVGDQ.m3u8"
autoplay
crossorigin="anonymous"
muted
playsinline
loop
>
<track kind="captions" src="/docs/demos/captions-button/captions.vtt" srclang="en" label="English" />
<track kind="subtitles" src="/docs/demos/captions-button/captions.vtt" srclang="es" label="Spanish" />
</hlsjs-video>
<div class="menu-bar">
<button type="button" commandfor="settings-menu" class="settings-trigger">Settings</button>
<media-menu id="settings-menu" side="top" align="end" class="menu">
<media-menu-content class="menu-content">
<media-menu-item commandfor="quality-menu" class="menu-item">
<span>Quality</span>
<span class="menu-value">
<span data-part="hint"></span>
<span aria-hidden="true">›</span>
</span>
</media-menu-item>
<media-menu-item commandfor="audio-menu" class="menu-item">
<span>Audio</span>
<span class="menu-value">
<span data-part="hint"></span>
<span aria-hidden="true">›</span>
</span>
</media-menu-item>
<media-menu-item commandfor="speed-menu" class="menu-item">
<span>Speed</span>
<span class="menu-value">
<span data-part="hint"></span>
<span aria-hidden="true">›</span>
</span>
</media-menu-item>
<media-menu-item commandfor="captions-menu" class="menu-item">
<span>Captions</span>
<span class="menu-value">
<span data-part="hint"></span>
<span aria-hidden="true">›</span>
</span>
</media-menu-item>
<media-menu-item class="menu-item">Copy link</media-menu-item>
</media-menu-content>
<media-menu-content id="quality-menu" class="menu-panel">
<media-menu-item class="menu-back">
<span aria-hidden="true">‹</span>
Quality
</media-menu-item>
<media-quality-radio-group class="menu-group">
<template>
<media-menu-radio-item class="menu-item">
<span>
<span data-part="label"></span>
<sup data-part="tier" class="menu-tier"></sup>
</span>
<span data-part="badge" class="menu-badge"></span>
<media-menu-item-indicator force-mount class="menu-indicator">✓</media-menu-item-indicator>
</media-menu-radio-item>
</template>
</media-quality-radio-group>
</media-menu-content>
<media-menu-content id="audio-menu" class="menu-panel">
<media-menu-item class="menu-back">
<span aria-hidden="true">‹</span>
Audio
</media-menu-item>
<media-audio-track-radio-group class="menu-group">
<template>
<media-menu-radio-item class="menu-item">
<span data-part="label"></span>
<media-menu-item-indicator force-mount class="menu-indicator">✓</media-menu-item-indicator>
</media-menu-radio-item>
</template>
</media-audio-track-radio-group>
</media-menu-content>
<media-menu-content id="speed-menu" class="menu-panel">
<media-menu-item class="menu-back">
<span aria-hidden="true">‹</span>
Speed
</media-menu-item>
<media-playback-rate-radio-group class="menu-group">
<template>
<media-menu-radio-item class="menu-item">
<span data-part="label"></span>
<media-menu-item-indicator force-mount class="menu-indicator">✓</media-menu-item-indicator>
</media-menu-radio-item>
</template>
</media-playback-rate-radio-group>
</media-menu-content>
<media-menu-content id="captions-menu" class="menu-panel">
<media-menu-item class="menu-back">
<span aria-hidden="true">‹</span>
Captions
</media-menu-item>
<media-captions-radio-group class="menu-group">
<template>
<media-menu-radio-item class="menu-item">
<span data-part="label"></span>
<media-menu-item-indicator force-mount class="menu-indicator">✓</media-menu-item-indicator>
</media-menu-radio-item>
</template>
</media-captions-radio-group>
</media-menu-content>
</media-menu>
</div>
</media-container>
</video-player>
.video-player media-container {
position: relative;
display: block;
}
.video-media {
width: 100%;
}
.menu-bar {
position: absolute;
right: 10px;
bottom: 10px;
}
.settings-trigger {
padding: 6px 16px;
color: black;
cursor: pointer;
background: rgba(255, 255, 255, 0.75);
border: 1px solid rgba(255, 255, 255, 0.35);
border-radius: 9999px;
backdrop-filter: blur(10px);
}
.menu {
--media-menu-side-offset: 8px;
--menu-transition-duration: 220ms;
position: relative;
box-sizing: border-box;
width: var(--media-menu-width);
min-width: 180px;
max-width: var(--media-menu-available-width, var(--media-popover-available-width, none));
height: var(--media-menu-height);
max-height: var(--media-menu-available-height, var(--media-popover-available-height, none));
padding: 6px;
overflow: hidden;
overscroll-behavior: none;
font-size: 14px;
color: white;
background: rgba(0, 0, 0, 0.88);
border-radius: 8px;
backdrop-filter: blur(10px);
transition-timing-function: ease-in-out;
transition-duration: var(--menu-transition-duration);
transition-property: width, height, opacity, filter;
}
.menu-content,
.menu-panel {
position: absolute;
inset: 0;
display: grid;
gap: 2px;
padding: 6px;
overflow: auto;
overscroll-behavior: none;
outline: none;
translate: 0 0;
transition-timing-function: ease-in-out;
transition-duration: var(--menu-transition-duration);
transition-property: translate, filter;
}
.menu-content[data-child-open] {
filter: blur(8px);
translate: -100% 0;
}
.menu-panel[data-submenu] {
z-index: 1;
}
.menu-panel[data-submenu][data-starting-style],
.menu-panel[data-submenu][data-ending-style] {
overflow: hidden;
pointer-events: none;
filter: blur(8px);
translate: 100% 0;
}
.menu-item,
.menu-back {
display: flex;
align-items: center;
justify-content: space-between;
min-height: 32px;
padding: 0 10px;
font: inherit;
color: inherit;
cursor: pointer;
background: none;
border: 0;
border-radius: 6px;
}
.menu-item[data-highlighted],
.menu-back:hover {
background: rgba(255, 255, 255, 0.16);
}
.menu-back {
gap: 8px;
justify-content: flex-start;
}
.menu-item[data-availability="unavailable"] {
display: none;
}
.menu-value {
display: inline-flex;
gap: 8px;
align-items: center;
color: rgba(255, 255, 255, 0.72);
}
.menu-value [aria-hidden] {
font-size: 18px;
line-height: 1;
}
.menu-back [aria-hidden] {
font-size: 18px;
line-height: 1;
color: rgba(255, 255, 255, 0.72);
}
.menu-group {
display: grid;
gap: 2px;
}
.menu-tier {
margin-left: 2px;
font-size: 10px;
}
.menu-badge {
margin-left: auto;
color: rgba(255, 255, 255, 0.72);
}
.menu-indicator {
opacity: 0;
}
media-menu-radio-item[aria-checked="true"] .menu-indicator {
opacity: 1;
}
import '@videojs/html/video/player';
import '@videojs/html/ui/container';
import '@videojs/html/media/hlsjs-video';
import '@videojs/html/ui/menu';
import '@videojs/html/ui/quality-radio-group';
import '@videojs/html/ui/audio-track-radio-group';
import '@videojs/html/ui/playback-rate-radio-group';
import '@videojs/html/ui/captions-radio-group';
API Reference
Rootmedia-menu
Props
| Prop | Type | Default | Details |
|---|---|---|---|
align | 'start' | 'center' | 'end' | 'start' | |
| |||
boundary | 'viewport' | 'container' | string & o... | — | |
| |||
closeOnEscape | boolean | true | |
| |||
closeOnOutsideClick | boolean | true | |
| |||
defaultOpen | boolean | false | |
| |||
open | boolean | false | |
| |||
side | 'top' | 'bottom' | 'left' | 'right' | 'bottom' | |
| |||
State
render, className, and style props.| Property | Type | Details |
|---|---|---|
transitionStarting | boolean | |
| ||
transitionEnding | boolean | |
| ||
open | boolean | |
status | 'idle' | 'starting' | 'ending' | |
side | 'top' | 'bottom' | 'left' | 'right' |... | |
| ||
align | 'start' | 'center' | 'end' | undefined | |
isSubmenu | boolean | |
| ||
CSS custom properties
| Variable | Details |
|---|---|
--media-menu-width | |
| |
--media-menu-height | |
| |
--media-menu-available-width | |
| |
--media-menu-available-height | |
| |
Events
| Event | Description |
|---|---|
open-change | Fired before the menu's open state changes. Cancel the event to prevent the change. |
CheckboxItemmedia-menu-checkbox-item
A checkbox-style menu item. Renders a <div> with role="menuitemcheckbox".
Props
| Prop | Type | Default | Details |
|---|---|---|---|
checked | boolean | — | |
| |||
disabled | boolean | — | |
| |||
Data attributes
| Attribute | Type | Details |
|---|---|---|
data-item | ||
| ||
data-highlighted | ||
| ||
Events
| Event | Description |
|---|---|
checked-change | Fired when the checked state changes. |
Contentmedia-menu-content
Accessible item and focus scope for exactly one root or nested menu page.
Events
| Event | Description |
|---|---|
open-change |
Groupmedia-menu-group
Groups related menu items. Renders a <div> with role="group".
GroupLabelmedia-menu-group-label
Non-interactive label for a group of items. Renders a <div>.
Itemmedia-menu-item
A single action in the menu. Renders a <div> with role="menuitem".
Props
| Prop | Type | Default | Details |
|---|---|---|---|
disabled | boolean | — | |
| |||
Data attributes
| Attribute | Type | Details |
|---|---|---|
data-item | ||
| ||
data-highlighted | ||
| ||
ItemIndicatormedia-menu-item-indicator
Visual indicator for a checked state. Only renders when checked is true (or forceMount is set).
Props
| Prop | Type | Default | Details |
|---|---|---|---|
checked | boolean | — | |
| |||
forceMount | boolean | — | |
| |||
PopupPopup
Positioned menu surface that contains one or more sibling Content pages.
RadioGroupmedia-menu-radio-group
A group of mutually exclusive radio items. Renders a <div> with role="group".
Props
| Prop | Type | Default | Details |
|---|---|---|---|
value | string | — | |
| |||
Events
| Event | Description |
|---|---|
value-change | Fired when the selected value changes. |
RadioItemmedia-menu-radio-item
A radio-style menu item. Renders a <div> with role="menuitemradio".
Props
| Prop | Type | Default | Details |
|---|---|---|---|
disabled | boolean | — | |
| |||
value | string | — | |
| |||
Data attributes
| Attribute | Type | Details |
|---|---|---|
data-item | ||
| ||
data-highlighted | ||
| ||
Separatormedia-menu-separator
Visual divider between groups of items. Renders a <div> with role="separator".
TriggerTrigger
Button that toggles the menu visibility. At root level renders a <button>. When inside a parent menu (as a submenu
trigger), renders as a <div role="menuitem"> that opens the submenu on click or ArrowRight.
Data attributes
| Attribute | Type | Details |
|---|---|---|
data-item | ||
| ||
data-highlighted | ||
| ||