Manual UI Behaviors hideOthers

hideOthers

elements man ui/behaviors/hide-others

Hides everything but an open modal part from assistive technology. It walks up from each kept element to <body> and sets aria-hidden="true" on every sibling along the way that holds no kept element, so a screen reader's virtual cursor stays in the modal menu or popover. Script, style, template, link and meta elements are left alone, and so are live regions, so announcements are still spoken.

Signature
function hideOthers(keep: Element | Element[]): () => void;
Argument Type Default What it does
keep Element | Element[] required The element or elements to leave readable: the content and its trigger. Elements not in the document are skipped.

One counter per element is shared by every caller: two overlays that hide the same sibling each count it, and it is shown again (its own earlier aria-hidden put back) only when the last of them releases. Releases may come in any order, and the release function does nothing the second time.

In a template of your own

app/shared/templates/action-menu/index.ehtml
import { hideOthers, pushLayer, type Layer } from "@elements/ui/behaviors"; interface ActionMenuState { trigger?: HTMLElement; layer?: Layer; unhide?: () => void; } function onOpen(ui: ActionMenuState, content: HTMLElement, close: () => void) { ui.layer = pushLayer(content, { onDismiss: close, inside: () => [ui.trigger], blockOutside: true }); ui.unhide = hideOthers([content, ui.trigger!]); } function onClose(ui: ActionMenuState) { ui.layer?.release(); ui.unhide?.(); } <ActionMenu (open: boolean = false, private ui: ActionMenuState = {})> <button type="button" aria-haspopup="menu" aria-expanded={open ? "true" : "false"} oninsert={(e) => ui.trigger = e.target as HTMLElement} onclick={() => open = !open}><slot name="trigger"/></button> <div e:if={open} role="menu" class="action-menu" oninsert={(e) => onOpen(ui, e.target as HTMLElement, () => open = false)} onremove={() => onClose(ui)}> <slot/> </div> </ActionMenu>

A modal menu: the layer blocks pointer interaction with the page, and hideOthers hides the page from a screen reader, so both kinds of user stay in the menu until it closes.

Writes

aria-hidden="true" on every sibling up to <body> that holds no kept element, counted and put back on the last release.

Used by

DropdownMenu (opens in a new tab), ContextMenu (opens in a new tab), Menubar (opens in a new tab).