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
- Yarn
npm install @rcarls/rc-adaptive-menu
yarn add @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-leadingdata-rc-menu-labeldata-rc-menu-trailingdata-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
| Property | Markup | Type | Default | Description |
|---|---|---|---|---|
label | label | string | 'Actions' | Accessible label for the toolbar. |
maxShown | max-shown | number | 3 | Maximum authored actions promoted ahead of the overflow trigger. A static declarative cap, re-evaluated whenever it changes — not a measurement of available space. |
open | open | boolean | Not specified | Whether the overflow menu is visible. Host writes are silent. |
defaultOpen | default-open | boolean | Not specified | Initial open state for uncontrolled usage. |
orientation | orientation | 'horizontal' | 'vertical' | 'horizontal' | Toolbar layout and arrow-key navigation axis. |
overflowLabel | overflow-label | string | 'More actions' | Accessible name for the overflow trigger and popup. |
$actions | JS property only | HTMLElement[] | Not specified | Original authored action elements in DOM order. |
$promotedActions | JS property only | HTMLElement[] | Not specified | Actions currently shown in the toolbar, in authored DOM order. |
$overflowedActions | JS property only | HTMLElement[] | Not specified | Actions currently assigned to the overflow menu, in authored DOM order. |
Methods
| Method | Description |
|---|---|
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
| Event | Detail type | Description |
|---|---|---|
rc-adaptive-menu-toggle | CustomEvent | Fired when user interaction requests a change to `open`. |
Slots
| Name | Description |
|---|---|
default | Direct native actions or supported rc action wrappers. |
overflow | Overflow-only actions and actions re-slotted by the component. |
overflow-icon | Optional decorative icon for the overflow trigger. |
CSS Custom Properties
| Property | Default | Description |
|---|---|---|
--rc-adaptive-menu-gap | var(--rc-control-gap) | Gap between promoted actions and the overflow trigger. |
--rc-adaptive-menu-trigger-inline-size | 2.5em | Overflow trigger minimum inline size. |
--rc-adaptive-menu-trigger-block-size | 2.5em | Overflow trigger minimum block size. |
--rc-adaptive-menu-touch-target-inline-size | Not specified | Minimum overflow trigger activation-area inline size. Defers to `--rc-adaptive-menu-touch-target-block-size` when unset. |
--rc-adaptive-menu-touch-target-block-size | 3rem | Minimum overflow trigger activation-area block size. |
--rc-adaptive-menu-touch-target-overlap-inline-start | 0px | Zero 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-end | 0px | The 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-padding | 0.5em | Overflow trigger padding. |
--rc-adaptive-menu-trigger-border | 1px solid ButtonBorder | Overflow trigger border. |
--rc-adaptive-menu-trigger-radius | var(--rc-control-radius) | Overflow trigger radius. |
--rc-adaptive-menu-trigger-background | ButtonFace | Overflow trigger background. |
--rc-adaptive-menu-trigger-color | ButtonText | Overflow trigger color. |
--rc-adaptive-menu-icon-size | 1.5em | Default overflow icon size. |
--rc-adaptive-menu-popup-min-inline-size | 10em | Overflow popup minimum inline size. |
--rc-adaptive-menu-popup-max-inline-size | calc(100dvi - 0.5rem) | Overflow popup viewport-aware inline limit. |
--rc-adaptive-menu-popup-max-block-size | calc(100dvb - 0.5rem) | Overflow popup viewport-aware block limit. |
--rc-adaptive-menu-popup-padding-block | 0.25em | Overflow popup block padding. |
--rc-adaptive-menu-popup-border | var(--rc-border) | Overflow popup border. |
--rc-adaptive-menu-popup-radius | var(--rc-control-radius) | Overflow popup radius. |
--rc-adaptive-menu-popup-background | var(--rc-surface) | Overflow popup background. |
--rc-adaptive-menu-popup-shadow | var(--rc-shadow) | Overflow popup shadow. |
--rc-adaptive-menu-popup-color | var(--rc-field-text) | Overflow popup foreground. |
--rc-adaptive-menu-item-min-block-size | 2.5em | Overflow action minimum block size. |
--rc-adaptive-menu-item-padding-block | var(--rc-item-padding-block) | Overflow action block padding. |
--rc-adaptive-menu-item-padding-inline | var(--rc-item-padding-inline) | Overflow action inline padding. |
--rc-adaptive-menu-item-gap | var(--rc-item-gap) | Overflow action content gap. |
CSS Parts
| Part | Description |
|---|---|
root | Toolbar container. |
overflow-trigger | Button that opens the overflow menu. |
popup | Overflow menu popover. |