Skip to content

<re-menu>

A custom-element wrapper for the menu-button pattern. It keeps light DOM and reuses every ARIA attribute; el.open reflects and controls the open state. See the custom elements overview for how the <re-*> tags work.

Import once to register the tag, then use it declaratively:

import "@relements/core/elements/re-menu";
Live example
<re-menu id="rm-1">
  <button
    type="button"
    class="re-button"
    data-variant="secondary"
    aria-haspopup="menu"
    aria-expanded="false"
    aria-controls="rm-1-panel"
    id="rm-1-btn"
  >
    Actions
  </button>
  <div class="re-menu__panel" role="menu" id="rm-1-panel" aria-labelledby="rm-1-btn" hidden>
    <button class="re-menu__item" role="menuitem" data-value="rename" id="rm-rename">
      Rename
    </button>
    <button class="re-menu__item" role="menuitem" data-value="duplicate" id="rm-duplicate">
      Duplicate
    </button>
    <button class="re-menu__item" role="menuitem" data-value="delete" id="rm-delete">
      Delete
    </button>
  </div>
</re-menu>
  • Keyboard — On the trigger button: Enter, Space, or ArrowDown open the menu and move focus to the first item; ArrowUp opens it and moves focus to the last item. Inside the menu: ArrowDown/ArrowUp move focus between items (wrapping at the ends), Home/End jump to the first/last item, Escape closes the menu and returns focus to the button, and Tab closes the menu without trapping focus. Clicking outside also closes it.
  • Focus — Items show a visible :focus-visible ring rendered as an inset box-shadow, so it stays clamped inside the menu panel’s edges. Activating an item or pressing Escape returns focus to the trigger button.
  • Semantics — The trigger is a native <button> carrying aria-haspopup="menu", aria-controls pointing at the panel, and aria-expanded, which the element keeps in sync with the open state (also reflected by el.open). The panel is role="menu", labelled by the button via aria-labelledby, with each entry a <button role="menuitem"> — assistive tech announces a menu and its item count.
  • Notes — This is a non-modal menu: it does not trap focus, and Tab moves on through the page after closing. Disabled items use aria-disabled="true"/disabled and are skipped by keyboard navigation. See the accessibility guide for the project-wide conventions.