Menu
A card of actions and options that slides out from under its key. The key stays down while the card is out; an option that is on lights its lamp.
Kit part · Dropdowns & menus
The menu’s own card, opened where you pointed: by right-click, by a long press on a touch screen, or from the keyboard with Shift F10 or the Menu key. The thing it opened on stays sunk while it is out.
Both finishes, side by side. Hover, pressed and focus are forced with .is-hover, .is-down and .is-focus; checked and disabled are real.
Aluminium
| Part | Rest | Hover | Long press held | Card out | Focus |
|---|---|---|---|---|---|
| Target | Score.wav | Score.wav | Score.wav | Score.wav | Score.wav |
Graphite
| Part | Rest | Hover | Long press held | Card out | Focus |
|---|---|---|---|---|---|
| Target | Score.wav | Score.wav | Score.wav | Score.wav | Score.wav |
| Name | Kind | Values | What it does |
|---|---|---|---|
| .tui-context | class | on the target | A target that has a menu: the context-menu cursor, a hairline on hover, and the sunk look while pressed or open. |
| data-menu-context | attribute | a menu id | On the target: names the .tui-menu it opens. Several targets can share one menu. |
| tabindex="0" · role="group" · aria-label | attribute | on the target | So the keyboard reaches it. Say “Context menu: Shift F10” in the label. |
| aria-haspopup="menu" · aria-keyshortcuts | attribute | "Shift+F10" | Tells assistive technology a menu is available, and how to reach it. |
| data-context-open | attribute | set by script | Present while the target’s card is out. The target stays down. |
| data-pressing | attribute | set by script | Present on a touch held towards the long press: the target sinks over the half second. |
| .tui-context__hint | class | — | A printed line that says how: “Right-click · long-press”. |
| .tui-menu | class | popover role="menu" | The card itself, with all of the menu part’s lines: actions, options, separators, danger, submenus. |
| LONG_PRESS_MS · LONG_PRESS_SLOP | constant | 500 · 10 | How long a touch is held, and how far it may drift, to be a long press. |
| pressDrifted(from, to, slop) | function | kit.mjs | Whether a touch has moved too far to still be a press. Pure. |
| Right-click · long press | pointer | — | Opens at the pointer with focus on the card; a scroll or a lift before half a second cancels the press. |
| Shift F10 · Menu key | keyboard | on the target | Opens at the target with the first line focused. Escape or a choice returns focus to the target. |
<div class="tui-context" tabindex="0" role="group"
data-menu-context="file-menu" aria-haspopup="menu" aria-keyshortcuts="Shift+F10"
aria-label="Score.wav, 3.4 MB. Context menu: Shift F10.">
Score.wav
</div>
<!-- The card is the menu part's own -->
<div class="tui-menu" id="file-menu" popover role="menu" aria-label="Score.wav">
<button role="menuitem" type="button" tabindex="-1">Open<kbd>Enter</kbd></button>
<button role="menuitem" type="button" tabindex="-1">Rename<kbd>F2</kbd></button>
<div role="separator"></div>
<button class="tui-menu__item--danger" role="menuitem" type="button" tabindex="-1">Delete<kbd>Del</kbd></button>
</div>import '/kit/kit.mjs'; // right-click, Shift+F10, the Menu key and the long press
// The lines act as any menu's do: aria-checked is already updated when this runs.
document.getElementById('file-menu').addEventListener('click', (e) => {
const line = e.target.closest('[role^="menuitem"]');
if (line) run(line.textContent.trim());
});Needs kit.css and kit.mjs. How to install the kit.
aria-keyshortcuts and aria-haspopup="menu" say it to assistive technology.The card and the whole keyboard are the menu’s: menu.mjs already opens any data-menu-context target from right-click, Shift F10 and the Menu key, and returns focus to it. context-menu.mjs adds the gesture a touch screen lacks. A pointer that is not a mouse starts a half-second timer on the target, which sinks into its recess as time passes; a move past 10px, a lift or a scroll clears it; if it runs out, the menu opens at the finger and the lift that follows is not taken as a click. Android reports the same press as a contextmenu event, which the module quietly absorbs so the card opens once.
A shortcut for people who know it is there: the same actions must live somewhere you can see.
5 rules in this file, with the foundations they rest on and the anti-patterns that break them. Full rules ship in the brain with the Pass.
A card of actions and options that slides out from under its key. The key stays down while the card is out; an option that is on lights its lamp.
Reserve
Kept for a power cut.
A card hung from the key that opened it, with a printed leader running back to the key. Not modal: the page stays live around it.
Every action and page behind one key: a modal plate whose entry line is a lit display, with the results printed below and the chosen one pressed in.