Skip to main content

rc-adaptive-menu

Priority-aware action toolbar that preserves authored controls while moving lower-priority actions into an overflow menu.

Package
@rcarls/rc-adaptive-menu
Element
<rc-adaptive-menu>
Native dependency
Consumer supplies buttons, links, or supported rc wrappers
State model
Controlled or uncontrolled open state
Main events
rc-adaptive-menu-toggle

Installation

npm install @rcarls/rc-adaptive-menu
import '@rcarls/rc-adaptive-menu/define';

Live demo

Change "Max shown" to see actions move between the toolbar and overflow menu. Clicking either presentation invokes the same authored control.

Action contract

Actions must be direct native buttons or links, or direct rc-button, rc-chip, or rc-menu-button wrappers. Larger numeric data-priority values are promoted first, up to max-shown authored actions; DOM order breaks ties. An authored slot="overflow" keeps an action overflow-only, regardless of max-shown.

max-shown is a static declarative cap, re-evaluated whenever it or an authored action's data-priority changes. The component performs no runtime size measurement of any kind, so promoted actions are not guaranteed to visually fit any particular container. A consumer whose promoted count needs to react to available space, such as a responsive breakpoint or a window size class, owns that decision and writes the resulting max-shown value down.

The component preserves node identity. It re-slots the original action and temporarily owns its menu role and tabindex, restoring authored values when the action is promoted, removed, or the component disconnects. There are no generated action proxies.

Themes can align action contents with rc-menu through these shared markers:

  • data-rc-menu-leading
  • data-rc-menu-label
  • data-rc-menu-trailing
  • data-rc-menu-shortcut

Open state

Use default-open to seed uncontrolled state. In controlled usage, write open and respond to rc-adaptive-menu-toggle; the event's detail.open contains the state requested by pointer or keyboard interaction. Host writes and calls to openMenu(), closeMenu(), or toggleMenu() are silent.

<rc-adaptive-menu id="actions" max-shown="2">
<button type="button">Edit</button>
<button type="button">Archive</button>
<button type="button">Delete</button>
</rc-adaptive-menu>

<script>
const menu = document.querySelector('#actions');

menu.addEventListener('rc-adaptive-menu-toggle', (event) => {
menu.open = event.detail.open;
});
</script>

The $actions, $promotedActions, and $overflowedActions getters return the current original elements in light-DOM order.

Accessibility

The promoted controls follow the APG toolbar pattern, including orientation- aware and right-to-left arrow navigation. Overflowed controls use menu-item roles, vertical menu navigation, Escape dismissal, light dismissal, and focus return. Without the Popover API, the same interaction remains available through an explicitly positioned fallback popup.

The overflow trigger's own accessible touch target is conventionally the trailing-most control in a toolbar, so it commonly leaves dead space before the container's own edge padding. --rc-adaptive-menu-touch-target-overlap-inline-end (zero by default) lets a theme or consumer give that space back so the trigger sits flush with the edge instead — the same pattern as rc-button's own touch-target overlap tokens.

API

Properties

PropertyMarkupTypeDefaultDescription
labellabelstring'Actions'Accessible label for the toolbar.
maxShownmax-shownnumber3Maximum authored actions promoted ahead of the overflow trigger. A static declarative cap, re-evaluated whenever it changes — not a measurement of available space.
openopenbooleanNot specifiedWhether the overflow menu is visible. Host writes are silent.
defaultOpendefault-openbooleanNot specifiedInitial open state for uncontrolled usage.
orientationorientation'horizontal' | 'vertical''horizontal'Toolbar layout and arrow-key navigation axis.
overflowLabeloverflow-labelstring'More actions'Accessible name for the overflow trigger and popup.
$actionsJS property onlyHTMLElement[]Not specifiedOriginal authored action elements in DOM order.
$promotedActionsJS property onlyHTMLElement[]Not specifiedActions currently shown in the toolbar, in authored DOM order.
$overflowedActionsJS property onlyHTMLElement[]Not specifiedActions currently assigned to the overflow menu, in authored DOM order.

Methods

MethodDescription
openMenu(focus: 'first' | 'last' | 'none')Opens the overflow popup silently and optionally focuses an edge action.
closeMenu(returnFocus: unknown)Closes the overflow popup silently.
toggleMenu(focus: 'first' | 'last' | 'none')Toggles the overflow popup silently.

Events

EventDetail typeDescription
rc-adaptive-menu-toggleCustomEventFired when user interaction requests a change to `open`.

Slots

NameDescription
defaultDirect native actions or supported rc action wrappers.
overflowOverflow-only actions and actions re-slotted by the component.
overflow-iconOptional decorative icon for the overflow trigger.

CSS Custom Properties

PropertyDefaultDescription
--rc-adaptive-menu-gapvar(--rc-control-gap)Gap between promoted actions and the overflow trigger.
--rc-adaptive-menu-trigger-inline-size2.5emOverflow trigger minimum inline size.
--rc-adaptive-menu-trigger-block-size2.5emOverflow trigger minimum block size.
--rc-adaptive-menu-touch-target-inline-sizeNot specifiedMinimum overflow trigger activation-area inline size. Defers to `--rc-adaptive-menu-touch-target-block-size` when unset.
--rc-adaptive-menu-touch-target-block-size3remMinimum overflow trigger activation-area block size.
--rc-adaptive-menu-touch-target-overlap-inline-start0pxZero by default. A theme or consumer sets this when the overflow trigger 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-adaptive-menu-touch-target-overlap-inline-end0pxThe trailing-edge counterpart to `--rc-adaptive-menu-touch-target-overlap-inline-start` — the overflow trigger is conventionally the trailing-most control in a toolbar, so this is the one commonly set.
--rc-adaptive-menu-trigger-padding0.5emOverflow trigger padding.
--rc-adaptive-menu-trigger-border1px solid ButtonBorderOverflow trigger border.
--rc-adaptive-menu-trigger-radiusvar(--rc-control-radius)Overflow trigger radius.
--rc-adaptive-menu-trigger-backgroundButtonFaceOverflow trigger background.
--rc-adaptive-menu-trigger-colorButtonTextOverflow trigger color.
--rc-adaptive-menu-icon-size1.5emDefault overflow icon size.
--rc-adaptive-menu-popup-min-inline-size10emOverflow popup minimum inline size.
--rc-adaptive-menu-popup-max-inline-sizecalc(100dvi - 0.5rem)Overflow popup viewport-aware inline limit.
--rc-adaptive-menu-popup-max-block-sizecalc(100dvb - 0.5rem)Overflow popup viewport-aware block limit.
--rc-adaptive-menu-popup-padding-block0.25emOverflow popup block padding.
--rc-adaptive-menu-popup-bordervar(--rc-border)Overflow popup border.
--rc-adaptive-menu-popup-radiusvar(--rc-control-radius)Overflow popup radius.
--rc-adaptive-menu-popup-backgroundvar(--rc-surface)Overflow popup background.
--rc-adaptive-menu-popup-shadowvar(--rc-shadow)Overflow popup shadow.
--rc-adaptive-menu-popup-colorvar(--rc-field-text)Overflow popup foreground.
--rc-adaptive-menu-item-min-block-size2.5emOverflow action minimum block size.
--rc-adaptive-menu-item-padding-blockvar(--rc-item-padding-block)Overflow action block padding.
--rc-adaptive-menu-item-padding-inlinevar(--rc-item-padding-inline)Overflow action inline padding.
--rc-adaptive-menu-item-gapvar(--rc-item-gap)Overflow action content gap.

CSS Parts

PartDescription
rootToolbar container.
overflow-triggerButton that opens the overflow menu.
popupOverflow menu popover.