Navigation
Command barLink to this section
CommandBar is a sticky site bar whose prompt is a real input. Give it commands, and a search for anything else; help lists them. Try help, ls, cd f then Tab, or a search such as mess.
const commands: Command[] = [ { name: "ls", description: "list the pages", run: () => ({ results: pages }), }, { name: "cd", usage: "cd <page>", description: "open a page", run: (args) => { const matches = pages.filter((page) => page.slug.startsWith(args)); return matches.length === 0 ? { message: `cd: no such page: ${args}`, tone: "error" } : { results: matches, complete: matches.length === 1 ? `cd ${matches[0].slug}` : undefined, }; }, },];
<CommandBar commands={commands} search={search} cwd="docs" actions={<a href="/contact/">contact</a>}/>;A command’s run gets everything after its name as the reader types, and returns what to print: results to choose from, a message, where Enter should go, and what Tab should complete to. In a string message, text in backticks is shown as a command, or as a key when it names one, such as `Enter`. search works like Search’s, and unavailable says why it failed; pass a function to tell failures apart.
/ or ⌘K (Ctrl K) focuses the prompt from anywhere, the arrow keys move through results, Enter opens one and Escape clears. What Tab would complete to shows faded after what’s typed, as in fish, and Tab or → at the end takes it. Commands are coloured as a shell would colour them, and one that isn’t found shows in red.
MenuLink to this section
Menu is a hamburger menu, for when a header runs out of room: put it in a CommandBar’s actions for small screens,
beside or instead of the links that don’t fit. Its three lines fold into a cross as it opens, and what it holds drops
in one after another.
<CommandBar actions={ <Menu class="sm:hidden"> <a href="/">projects</a> <a href="/memos/" aria-current="page"> memos </a> <a href="/contact/">contact</a> </Menu> }/>It holds whatever you give it. Links are styled for you, and whichever has aria-current="page" is marked; which link
that is is up to your app, which knows its own routes. Buttons and other controls work too.
It behaves the same way every time. It closes on Escape (handing focus back to its button), a click anywhere else, tabbing out of it, or choosing a link or button inside. The arrow keys, Home and End move between what’s inside, wrapping round; opening it from the keyboard, with Enter, Space or the down arrow, moves straight to the first.
BreadcrumbsLink to this section
<Breadcrumbsbackitems={[{ label: "projects", href: "/" }, { label: "place-images" }]}/>Link cardsLink to this section
For a short list of next steps. accent marks the one to pick first, and arrow changes the arrow.
<LinkCard href="mailto:me@example.com">Email me</LinkCard><LinkCard href="/cv.pdf" download="cv.pdf" tone="accent" arrow="↓">Download my CV</LinkCard>For a card of your own, such as one with a picture and a summary, cardClass gives the same surface, border and shadow. Pass interactive: true when the card is a link, so it lifts on hover and shows the focus ring.
<a href="/places/" class={cardClass({ interactive: true })}> …</a>design-system is a Ben Hodgson projectGitHub