Navbar and Navigation Menu
Navbar and Navigation Menu: anatomy, keyboard behavior, state, and theming in Askr.
Example
import { NavigationMenu, NavigationMenuItem, NavigationMenuLink, NavigationMenuList } from '@askrjs/themes/components';
<NavigationMenu aria-label="Primary navigation">
<NavigationMenuList>
<NavigationMenuItem><NavigationMenuLink href={projectsRoute}>Projects</NavigationMenuLink></NavigationMenuItem>
<NavigationMenuItem><NavigationMenuLink href={reportsRoute}>Reports</NavigationMenuLink></NavigationMenuItem>
</NavigationMenuList>
</NavigationMenu>Purpose
Despite the page title, the only export at @askrjs/themes/navigation-menu is NavigationMenu and its parts — there's no separate Navbar primitive on this subpath. Use these pieces to build a horizontal menu bar with flyout content: a top-level list of items, each optionally opening a panel of links. If you actually want the responsive app-header component (with a collapsing hamburger state), that's Navbar from the general themes component barrel, not this one.
Install and import
tsx
import {
NavigationMenu,
NavigationMenuList,
NavigationMenuItem,
NavigationMenuTrigger,
NavigationMenuContent,
NavigationMenuLink,
NavigationMenuViewport,
NavigationMenuIndicator,
} from '@askrjs/themes/navigation-menu';
This subpath is an alias into the shared components barrel, so importing the same names from @askrjs/themes/components` works identically.
Live examples
The example composes NavigationMenu with a NavigationMenuList of NavigationMenuItem/NavigationMenuLink pairs, and passes route destinations rather than hand-written path strings. Note the aria-label on the menu itself: with more than one navigation landmark on a page, each needs its own name for that landmark list to be usable.
Anatomy
NavigationMenu renders a <nav>, NavigationMenuList an <ul>, and NavigationMenuItem an <li> — a plain nested list under the hood. NavigationMenuTrigger is a real <button type="button"> (with the nav-item class baked in), while NavigationMenuContent, NavigationMenuLink, NavigationMenuViewport, and NavigationMenuIndicator are generic slotted elements (a div, an anchor, a div, and a div respectively) that only exist to give you stable markup and data-slot hooks for the flyout panel, its links, the clipping viewport, and an active-tab indicator strip.
State model
None of these components track open/closed state, active item, or hover intent — there's no internal store or context here at all. You decide which trigger's content is visible, typically with a bit of local state or by composing NavigationMenuTrigger/NavigationMenuContent with the interaction primitives from @askrjs/ui. The themed Navbar gives you two different worked examples of that pattern, for two different jobs: its mobile hamburger collapse is built on Collapsible/CollapsibleTrigger/CollapsibleContent, while a per-item flyout (NavDropdown) is built on Dropdown/DropdownTrigger/DropdownContent — pick whichever matches what you're building rather than assuming one mechanism covers both. Treat this package as markup, not behavior.
Keyboard and accessibility
Because NavigationMenu is a <nav> and NavigationMenuTrigger is a genuine <button>, you get landmark navigation and native Tab/Enter/Space activation for free. What you don't get automatically is aria-expanded, aria-controls, or Escape-to-close on the trigger/content pair, or arrow-key movement across items — those are your responsibility to wire up if you're building a real dropdown-style flyout rather than a flat link list.
Styling and tokens
Every part carries a data-slot attribute — navigation-menu, navigation-menu-list, navigation-menu-item, navigation-menu-trigger, navigation-menu-content, navigation-menu-link, navigation-menu-viewport, navigation-menu-indicator — and the trigger additionally gets the nav-item class. Style off those hooks instead of assuming a fixed DOM shape, since as/asChild let consumers swap the underlying element.
API
NavigationMenu, NavigationMenuList, and NavigationMenuItem accept the shared CatalogComponentProps shape, including as to render a different tag. NavigationMenuTrigger is built on the same internal button-part helper as the rest of the catalog's button-flavored components, and that helper accepts asChild but silently discards as — passing it has no effect, it always renders a real <button> unless you use asChild. asChild itself hands rendering off to a Slot (useful for wrapping your router's Link) on every part, plus class, children, ref, and arbitrary passthrough attributes are supported throughout. NavigationMenuTrigger also accepts a type override, though it defaults to "button" so it never accidentally submits a form.
Edge cases
Multi-level or mega-menu content is entirely on you to lay out inside NavigationMenuContent — there's no built-in positioning or collision handling in NavigationMenuViewport, it's just a slotted div. Since there's no shipped open state, SSR is trivially safe (everything renders closed/static by default), but that also means client hydration has to attach whatever interaction logic you add. If you need real click-outside dismissal or focus trapping for a flyout, reach for @askrjs/ui's dropdown primitives rather than assuming this package provides it.
Related pages
See Sidebar and Menubar for the other two navigation-chrome building blocks, Application Chrome for how these fit into a full page shell, and Breadcrumb and Pagination for the smaller wayfinding controls that often sit alongside a nav bar.