COMPONENT
Menu
A list of destinations — the alphabet every navigation in this system is spelled in. Stacked or in a row, with headings, nesting and collapsible groups, and not a line of JavaScript in any of it.
Stacked, with a heading, a fold and an inert row
Open the fold with Enter or Space on it. That is a <details> element, so the toggle, the keyboard and the announcement are the browser's.
<ul class="menu">
<li class="menu-title">SECTIONS</li>
<li><a class="menu-item" href="#work" aria-current="page">Work</a></li>
<li><a class="menu-item" href="#craft">Craft</a></li>
<li><a class="menu-item" href="#process">Process</a></li>
<li>
<details class="menu-fold">
<summary class="menu-item menu-fold-head">
Writing
<span class="caret" aria-hidden="true">▾</span>
</summary>
<ul class="menu-group">
<li><a class="menu-item" href="#journal">Journal</a></li>
<li><a class="menu-item" href="#notes">Filed notes</a></li>
</ul>
</details>
</li>
<li>
<span class="menu-item" aria-disabled="true" title="Nothing recorded yet.">Talks</span>
</li>
</ul>The same list, along a row
One class different. It wraps rather than scrolling or hiding, so narrowing the container never removes a destination.
<ul class="menu menu-inline">
<li><a class="menu-item" href="#work" aria-current="page">Work</a></li>
<li><a class="menu-item" href="#craft">Craft</a></li>
<li><a class="menu-item" href="#process">Process</a></li>
<li><a class="menu-item" href="#journal">Journal</a></li>
<li><span class="menu-item" aria-disabled="true" title="Nothing recorded yet.">Talks</span></li>
</ul>Reference
Read from components/menu.css when this page was built, so it cannot fall behind the stylesheet.
.menu.menu-inline.menu-group.menu-title.menu-item.menu-fold.menu-fold-head.caret--ds-accent--ds-focus-ring-inset--ds-focus-width--ds-font-display--ds-gap--ds-gap-inline--ds-hit-min--ds-ink--ds-ink-disabled--ds-ink-faint--ds-ink-soft--ds-menu-indent--ds-motion-fast--ds-nav-gap--ds-pad-chip--ds-radius-nav--ds-raised--ds-text-meta--ds-text-ui--ds-track-meta--ds-track-subtleNotes
There is no role="menu" here and there never will be. That role promises arrow-key roving focus, which no stylesheet can deliver, and a promise made in ARIA and broken in behaviour is worse than the plain markup it replaced. Tab walks it — that is the whole keyboard contract, and it is the platform's.
The open state, the keyboard, the announcement and the toggle all belong to the element, for free and correctly. A div with a class needs script for every one of them and gets the announcement wrong when it has it. The only thing the stylesheet does is take away the browser's own triangle, because .caret is already pointing — and two markers disagreeing about which way is open is worse than either alone.
.menu-item stands on its own and does not need .menu around it. A .dropdown-panel holds rows directly, with no list, because a handful of choices is not a structure. Reach for .menu the moment there is a heading, a nesting, or more than a few.
The current row states itself twice — a raised ground and the accent ink — because colour alone is not a signal everyone receives. An unavailable row is drawn inert rather than dropped: aria-disabled plus a title saying why. Removing it would re-lay out the list under a cursor already on its way down, and would hide the fact that the destination exists at all.
A truncated destination is a destination the reader cannot identify. The supported floor for an atom is 200px, and two words of display type do not fit on one line there — so they take two.