Skip to main content

rc-menu-button

Trigger button that opens an rc-menu popup, following the WAI-ARIA Menu Button pattern.

Package
@rcarls/rc-menu-button
Element
<rc-menu-button>
Native dependency
Requires trigger and menu children
State model
Controlled or uncontrolled open state
Main events
rc-menu-button-toggle

Installation​

npm install @rcarls/rc-webcomponents@next
import '@rcarls/rc-webcomponents/rc-menu-button/define';

Usage​

Put a native button in the trigger slot and an rc-menu in the default slot.

<rc-menu-button>
<button slot="trigger">File</button>
<rc-menu label="File">
<button>New</button>
<button>Open…</button>
<button>Save</button>
</rc-menu>
</rc-menu-button>

Live demo​

Accessibility​

The element sets aria-haspopup="menu" on the trigger and keeps its aria-expanded in step with open. Choosing an item or pressing Escape closes the menu and returns focus to the trigger; a click outside closes it without moving focus.

KeyAction
Enter, SpaceOpens the menu.
Down ArrowOpens the menu and focuses the first item.
Up ArrowOpens the menu and focuses the last item.
EscapeCloses the menu and returns focus to the trigger.

Inside the open menu, the rc-menu keys apply. In a vertical layout, such as a submenu or a vertical menubar, Right Arrow opens on the first item and Left Arrow on the last, and these keys turn with right-to-left and vertical writing modes. See the WAI-ARIA Menu Button pattern.

Theming​

The default demo mode shows the component without a package theme. Use the shared preview controls on this page to compare inherited, light, and dark color schemes or to apply the optional Material theme only inside the demo frames.

rc-menu-button keeps the consumer-supplied trigger in light DOM and styles it through inherited --rc-menu-button-trigger-* custom properties. The popup menu remains an rc-menu, so menu row styling continues through the --rc-menu-* contract.

Add icon-only when the trigger has no visible label. Supporting themes can then size the visible trigger with --rc-menu-button-icon-size while preserving an independently configurable activation area through the --rc-menu-button-touch-target-* properties.

At an edge with no neighbor on that side, such as a toolbar's trailing-most trigger, --rc-menu-button-touch-target-overlap-inline-start and -inline-end (zero by default) let a theme or consumer give that reserved space back so the visible trigger sits flush with the edge instead, using the same pattern as rc-button's own touch-target overlap tokens.

API​

Properties​

PropertyMarkupTypeDefaultDescription
openopenbooleanNot specifiedApplies open state in controlled mode without dispatching an event.
defaultOpendefault-openbooleanNot specifiedApplies the uncontrolled default before any controlled write occurs.
orientationorientation'horizontal' | 'vertical' | undefinedNot specifiedThe layout this menu button sits in, which picks the arrow keys that open and close the menu. `horizontal` runs along the inline axis and `vertical` along the block axis; the keys follow how that layout renders. If not set, inherits from a parent rc-menubar or element with role="menubar".
placementplacementAnchorPlacement'block-end-start'Preferred placement of the popup relative to the trigger button. Reads the default until the author sets one.

Methods​

MethodDescription
openMenu(focusTarget: 'first' | 'last')Opens the menu and moves focus into it.
closeMenu(returnFocus: unknown)Closes the menu.
toggleMenu()Toggles the menu between open and closed.
focus(options?: FocusOptions)Overrides the default focus() so that programmatic focus calls (e.g. from a roving-tabindex parent navigating back to this element via arrow keys) always reach the trigger. Chrome's delegatesFocus will not delegate to a tabindex="-1" element, so when the toolbar marks this host inactive it suppresses the trigger — and the next focusItem() call silently fails. Lifting the suppression here and directly calling trigger.focus() bypasses that restriction.

Events​

EventDetail typeDescription
rc-menu-button-toggleCustomEventFired when the menu opens or closes

Slots​

NameDescription
triggerThe button element that triggers the menu
indicatorOptional decorative indicator rendered at the trigger's inline end
defaultThe rc-menu element to display as popup

CSS Custom Properties​

PropertyDefaultDescription
--rc-menu-button-trigger-block-sizevar(--rc-control-block-size)Minimum block size of the trigger
--rc-menu-button-trigger-padding-blockvar(--rc-control-padding-block)Trigger block-axis padding
--rc-menu-button-trigger-padding-inlinevar(--rc-control-padding-inline)Trigger inline-axis padding
--rc-menu-button-trigger-gapvar(--rc-item-gap)Gap between flex children in the trigger
--rc-menu-button-trigger-bordervar(--rc-border)Trigger border
--rc-menu-button-trigger-radiusvar(--rc-control-radius)Trigger border radius
--rc-menu-button-trigger-backgroundvar(--rc-button-bg)Trigger background
--rc-menu-button-trigger-colorvar(--rc-button-text)Trigger text color
--rc-menu-button-trigger-transitionNot specifiedCSS transition applied to the trigger
--rc-menu-button-trigger-hover-backgroundcolor-mix(in srgb, Highlight 8%, transparent)Trigger hover background
--rc-menu-button-trigger-hover-colorinheritTrigger hover text color
--rc-menu-button-trigger-hover-border-colorcurrentColorTrigger hover border color
--rc-menu-button-trigger-open-backgroundcolor-mix(in srgb, Highlight 12%, transparent)Trigger background when the menu is open
--rc-menu-button-trigger-open-colorinheritTrigger text color when the menu is open
--rc-menu-button-trigger-open-border-colorcurrentColorTrigger border color when the menu is open
--rc-menu-button-indicator-size1emInline and block size of the slotted indicator
--rc-menu-button-indicator-colorcurrentColorColor of the slotted indicator
--rc-menu-button-indicator-insetvar(--rc-menu-button-trigger-padding-inline)Indicator distance from the trigger's inline end
--rc-menu-button-icon-sizeNot specifiedInline size of an `icon-only` trigger's visible box. Square by default (equal to `--rc-menu-button-trigger-block-size`); set narrower or wider to change only the trigger's width, independent of its height.
--rc-menu-button-touch-target-block-size3remMinimum accessible touch target block size for an `icon-only` trigger. A floor, not a fixed size: has no effect once `--rc-menu-button-trigger-block-size` already meets or exceeds it. Grows the shadow-DOM trigger wrapper (reserving layout space) and the light-DOM hit-slop (the actual larger clickable region) together; the visible trigger itself stays at its own size, centered.
--rc-menu-button-touch-target-inline-sizeNot specifiedMinimum accessible touch target inline size for an `icon-only` trigger. Defers to `--rc-menu-button-touch-target-block-size` when unset.
--rc-menu-button-touch-target-overlap-inline-start0pxZero by default. A theme or consumer sets this on an `icon-only` trigger that sits at a real leading edge (no neighbor on that side) to let its touch-target inflation overlap into whatever sits just outside the host, such as a container's own edge padding, instead of also reserving layout space there.
--rc-menu-button-touch-target-overlap-inline-end0pxThe trailing-edge counterpart to `--rc-menu-button-touch-target-overlap-inline-start`.
--rc-menu-button-popup-duration150msPopup open/close fade transition duration.

CSS Parts​

PartDescription
rootThe root container element
popupThe popup container element