VIII Wayfinding

Star on GitHubFeedback
VIII WayfindingRadixot-navmenu

Navigation menu

Small words open a panel of large names, the scale contrast of a poster; or a contents page with one name set as the headline; or the names opened into the line itself.

Report an issue with Navigation menu

Example

Names
Lead
Inline, press a word

Install

Run it in a project that has the shadcn CLI set up. It brings the 0nlyType base along.

npx shadcn@latest add https://thedirectors.agency/ui/r/navigation-menu.json

Usage

navigation-menu-example.tsx
"use client"import {NavigationMenu,NavigationMenuContent,NavigationMenuItem,NavigationMenuLink,NavigationMenuList,NavigationMenuTrigger,type NavigationMenuProps,} from "@/components/ui/navigation-menu"const menu = {Work: [["Identity", "Names, marks, and the rules that keep them"],["Websites", "Built to be read slowly and used for years"],["Motion", "Titles, idents and things that move once"],],Studio: [["People", "Six of us, in Stockholm and Lisbon"],["Process", "How a project runs, week by week"],["Journal", "Notes on type, space and slowness"],],}type Menu = Pick<NavigationMenuProps, "variant" | "value"> & { label: string; force?: string }function Studio({ variant, value, label, force }: Menu) {return (<NavigationMenu aria-label={label} variant={variant} value={value}><NavigationMenuList>{Object.entries(menu).map(([word, names], i) => (<NavigationMenuItem key={word} value={word.toLowerCase()}><NavigationMenuTrigger data-force={i === 0 ? force : undefined}>{word}</NavigationMenuTrigger><NavigationMenuContent>{names.map(([name, line]) => (<NavigationMenuLink key={name} href={`#${name.toLowerCase()}`}>{name}<small>{line}</small></NavigationMenuLink>))}</NavigationMenuContent></NavigationMenuItem>))}<NavigationMenuItem><NavigationMenuLink href="#contact">Contact</NavigationMenuLink></NavigationMenuItem></NavigationMenuList></NavigationMenu>)}export default function Example() {return (<div className="grid w-full gap-12"><div className="grid content-start gap-3" style={{ minHeight: "17rem" }}><span className="ot-label">Names</span><Studio label="Studio" /></div><div className="grid content-start gap-3" style={{ minHeight: "19rem" }}><span className="ot-label">Lead</span><Studio label="Studio, as contents" variant="lead" /></div><div className="grid content-start gap-3"><span className="ot-label">Inline, press a word</span><Studio label="Studio, in a line" variant="inline" /></div></div>)}

Contract

  • Underneath: Radix NavigationMenu.
  • Anatomy: <nav class="ot-navmenu"> of small trigger buttons (aria-expanded, aria-controls) and .ot-navmenu-panel panels of large links.
  • Small words open a panel of large names, the scale contrast of a poster. The panel's rule draws across, the names arrive in turn, and the trigger's arrow turns. It opens on pointing (after a short wait) or pressing, and closes on leaving.
  • variant on the root (data-variant): names (the default), lead or inline.
  • lead: a magazine's contents page, and WOVE's "03 Ambient". The names stand small (mp, graphite) in a narrow column; the one pointed at or focused (the first, at first) is inked there and set beside the column as the headline at ff 200, its <small> line under it in graphite. The headline is an aria-hidden copy (.ot-navmenu-lead); the links keep their own names. Below 40rem the headline stands down and the names keep their lines.
  • inline: "Healthy habits → for creatives", one line of thought. The trigger's arrow is → (← right to left). A press, never a passing pointer, opens the names into the line after the word, larger (mf 200) on the same baseline; the words after it make room, and the other words step back to pencil. The <small> lines stay for screen readers only. Below 40rem the names drop to mp and may wrap.
  • Keyboard: Enter or Space toggles a panel; Escape closes it and returns focus to its trigger. Tab moves from an open trigger into its names. Without a dir, the menu takes the direction of the page around it as it mounts, so it mirrors on a right-to-left page. It reads it once, at mount, as the menus do: a page that changes dir afterwards passes dir itself, or remounts the menu.

Props

Props of Navigation menu
PropTypeDefaultWhat it does
NavigationMenu variant"names" | "lead" | "inline""names"names: a panel of large names hung under the menu. lead: the names small in a narrow column, and the one you point at or focus (the first, at first) set beside them as the headline with its <small> line; below 40rem the names keep their lines instead. inline: a press (not a passing pointer) opens the names into the line after the word, larger, on one baseline; the words after make room and the others step back to pencil.
NavigationMenu dir"ltr" | "rtl"Left out, the menu takes the direction of the page around it as it mounts, so on a right-to-left page its words run from the right and the arrow keys follow.
NavigationMenuTriggerbuttonA small word. Its ↓ turns over while the panel is open. Opens on pointing after a short wait, or on Enter and Space.
NavigationMenuContentdivThe panel, hung under the whole menu. Its children are NavigationMenuLinks, each a large name with an optional <small> line. Its rule draws across and the names arrive in turn.
NavigationMenuLinkaInside a panel, a large name. Directly in an item, a small word like a trigger. asChild renders your own link.
delayDuration / skipDelayDurationnumberRadix's pointer waits, on NavigationMenu.

Craft

Where its move comes from

Where its move comes from
ComponentReferenceMove
Navigation menuPOINT / SPECTRASmall words open large names
Lead navigation menuWOVE; a magazine's contents pageThe name you point at stands as the headline beside the list
Inline navigation menu"Healthy habits → for creatives"The names open into the line of thought

How it moves

How it moves
ComponentArticulationWhat moves
Navigation menuArpeggioThe rule draws across; the names arrive; the arrow turns
Lead navigation menuStep upThe name you point at steps up into the headline
Inline navigation menuOpeningThe line opens after the word and the words after it make room; the arrow inks and leans toward the names