Context menu
hc-context-menu shows a menu where the user right-clicks, the shadcn
ContextMenu equivalent. It reuses the Menu
surface entirely — same .hc-menu markup, items, separators, labels,
and menuitemcheckbox / menuitemradio — so there is no new CSS.
The only difference is how it opens: at the pointer, via the
contextmenu event, instead of anchored to a trigger button.
The behavior lives in installContextMenu.
Basic usage
Section titled “Basic usage”Add data-hc-context-menu="<menu-id>" to the region that should show a
custom menu on right-click, and point it at a .hc-menu popover.
Right-click (or focus + Shift+F10) inside this box.
<div data-hc-context-menu="file-ctx">…right-clickable region…</div>
<div class="hc-menu" id="file-ctx" popover role="menu" aria-label="File actions"> <button class="hc-menu__item" role="menuitem" type="button">Open</button> <button class="hc-menu__item" role="menuitem" type="button">Rename</button> <button class="hc-menu__item" role="menuitemcheckbox" aria-checked="false" type="button">Bookmark</button> <hr class="hc-menu__separator"> <button class="hc-menu__item" role="menuitem" type="button" data-variant="error">Delete</button></div>The menu surface is identical to the dropdown Menu,
so everything documented there — menuitemcheckbox / menuitemradio,
group labels, the destructive data-variant="error" item — works here
too.
JavaScript
Section titled “JavaScript”import { installContextMenu } from '@hypermedia-components/core';installContextMenu(); // idempotent; returns an uninstallerThe zero-config @hypermedia-components/core/behaviors entry installs
it automatically.
Opening and keyboard
Section titled “Opening and keyboard”- Right-click (and touch long-press, and the keyboard Menu
key) fire the
contextmenuevent; the behavior cancels the native menu withpreventDefault()and opens the popover at the pointer, clamped to stay inside the viewport. Shift+F10opens the menu at the focused element. This is handled separately becauseShift+F10does not fire acontextmenuevent. For it to reach the behavior, the region (or a focusable descendant) must be able to hold focus — addtabindex="0"to a generic region, or rely on the focusable rows / controls inside it.
Once open, navigation is the standard menu keyboard contract: ↓ / ↑
move between items, Home / End jump to the first / last enabled
item, first-letter type-ahead, Tab and Escape close. Disabled items
are skipped. Escape / outside-click dismissal and focus restoration
come from the native popover.
The select event
Section titled “The select event”Selecting an item dispatches the same bubbling hc:menuselect event as
the dropdown menu, plus a contextTarget — the element that was
right-clicked:
menu.addEventListener('hc:menuselect', (e) => { const { item, contextTarget, checked } = e.detail; // contextTarget is the element the menu was opened on — e.g. the row // or file the action applies to.});Plain menuitems close the menu after selection; menuitemcheckbox /
menuitemradio keep it open so several can be toggled.
Submenus
Section titled “Submenus”Context menus share the dropdown’s submenu support: give a menuitem a
data-hc-submenu="<id>" pointing at a nested .hc-menu. Hover or press
→ to open it, ← / Esc to close, and selecting
a leaf closes the whole tree. See
Menu → Submenus for the
full markup and interaction model.
htmx usage
Section titled “htmx usage”Wire a request straight off hc:menuselect, using the right-clicked
element to scope the action:
<ul id="files"> <li data-hc-context-menu="row-ctx" data-id="42">report.pdf</li> …</ul>
<div class="hc-menu" id="row-ctx" popover role="menu" aria-label="Row actions" data-hx-post="/files/delete" data-hx-trigger="hc:menuselect" data-hx-include="this"> <button class="hc-menu__item" role="menuitem" type="button" data-variant="error">Delete</button></div>Read event.detail.contextTarget.dataset.id in an htmx:configRequest
handler to attach the target row’s id to the request.
Hyperscript
Section titled “Hyperscript”Act on the right-clicked row inline — detail.contextTarget is the
element the menu opened on:
<div class="hc-menu" id="row-ctx" popover role="menu" aria-label="Row actions" _="on hc:menuselect call rowAction(event.detail.item.dataset.action, event.detail.contextTarget)"> …</div>More patterns: Hyperscript → Reacting to component events.
Accessibility
Section titled “Accessibility”- The popup uses
role="menu"withmenuitemchildren — the same WAI-ARIA APG menu pattern as the dropdown. - Provide a keyboard path: the Menu key works through the
contextmenuevent, andShift+F10is handled explicitly — but only if the region can receive focus. Make the region or its rows focusable. - Don’t rely on the context menu as the only way to reach an action; mirror destructive / important actions in a visible control or a dropdown menu too.
Theming tokens
Section titled “Theming tokens”None of its own — it renders the Menu
surface, so the menu.* tokens (and the --hc-menu-* variables) drive
its appearance.
Related
Section titled “Related”- Menu — the same surface, opened from a trigger button.
- Toggle group — for persistent inline choices rather than a transient action list.