Morph navPro

A navigation bar that morphs into rich menus, search, and a compact state as one surface.

Live · keyboard ready

Plan the quarter without the spreadsheet

Fieldwork keeps roadmaps, specs, and status in one calm workspace.

Roadmaps that stay honest

Cycles close on their own dates, and slipped work carries its history with it.

Specs next to the work

Docs link to the issues they describe, so a changed scope shows up in both.

Status without meetings

Weekly updates draft themselves from what actually moved.

Built for large teams

SSO, audit logs, and granular roles for teams of 50 to 5,000.

  • The top navigation of a marketing or product site with a few sections that each hold several destinations.
  • Headers where search should grow out of the bar instead of opening a separate modal.
  • Sites that want one primary action, such as Sign up, pinned to the end of the bar.
  • Use liquid-tab-bar for an app-style switcher between a handful of peer sections.
  • Use tabs for switching views inside a page.
  • Use dropdown-menu when you only need one menu of commands, not site navigation.

Installation

Pro source and install commands unlock with a Pro plan.

example.tsx
import { MorphNav } from "@/registry/components/morph-nav/morph-nav"; export function SiteHeader({ scrolled }: { scrolled: boolean }) {  return (    <MorphNav      brand={{ name: "Arc", mark: <Logo />, href: "/" }}      items={[        { value: "product", label: "Product", links: [          { label: "Components", description: "Motion-first building blocks", href: "/components" },          { label: "Blocks", description: "Full sections", href: "/blocks" },        ] },        { value: "pricing", label: "Pricing", href: "/pricing" },      ]}      search={{ items: [{ label: "Dialog", group: "Components", href: "/components/dialog" }] }}      action={{ label: "Sign up", href: "/sign-up" }}      current="product"      compact={scrolled}    />  );}

Tighten on scroll

example.tsx
const [scrolled, setScrolled] = useState(false);useEffect(() => {  const onScroll = () => setScrolled(window.scrollY > 24);  window.addEventListener("scroll", onScroll, { passive: true });  return () => window.removeEventListener("scroll", onScroll);}, []); <MorphNav items={items} current={section} compact={scrolled} onNavigate={d => d.href && router.push(d.href)} />

MorphNav

A site navigation bar made of one continuous surface: a highlight glides between items, items with links grow the bar into a dropdown panel, and search morphs out of the bar itself.

PropTypeDefaultDescription
itemsRequired{ value: string; label: string; href?: string; links?: { label: string; description?: string; icon?: ReactNode; href?: string }[]; columns?: 1 | 2; feature?: ReactNode; footer?: ReactNode }[]–Top level destinations. Items with links or a feature open a panel; other items act as plain links. columns defaults to 2 when there are more than three links. Clicking a link or button inside feature closes the panel.
brand{ name: string; mark: ReactNode; href?: string }–Brand button at the start of the bar.
action{ label: string; icon?: ReactNode; href?: string; onClick?: () => void }–The one primary action at the end of the bar.
search{ placeholder?: string; items: { label: string; description?: string; group?: string; icon?: ReactNode; href?: string; keywords?: string }[] }–Search entries. Leave it out to hide search.
currentstring–Value of the item that holds the current page.
compactbooleanfalseTightens the bar, for example once the page scrolls.
collapseBelownumber720Below this container width in px the items fold into one menu.
onNavigate(destination: { label: string; href?: string; section?: string }) => void–Called for every destination: links, search results, plain items, and the brand.
labelstring"Main"Accessible name of the nav landmark.
classNamestring–Extra class on the nav element.
ArrowLeftorArrowRight
Moves between top level items, wrapping; an open panel follows to the new item.
HomeorEnd
Focuses the first or last item.
ArrowDownorEnterorSpace
On an item with a panel, opens it and moves focus to its first link. If the panel is already open, moves focus into it.
ArrowUporArrowDown
Inside a panel, moves between links; ArrowUp on the first link returns to the trigger. In search, moves the active result.
Enter
In search, opens the active result.
Escape
Closes search or the open panel and returns focus to where it came from.
  • Renders a nav landmark; the current item carries aria-current="page" and panel triggers use aria-expanded and aria-controls.
  • Open panels are regions labelled by their trigger; the panel closes when focus leaves the nav.
  • Search is a combobox driving a listbox with aria-activedescendant, and the result count is announced politely. With an empty query it lists the first five entries as Suggested.
  • A pointer down outside the nav closes the panel or search.
  • The surface springs to each panel's size, with a little bounce when it grows and none when it shrinks. Moving to a neighbour slides the new panel in from that side while a highlight glides between items.
  • Hover opens a panel after a 60ms intent delay and leaving the nav closes it after 180ms, so crossing a gap does not flicker it shut.
  • Search grows out of the same surface as the bar fades and blurs away; compact and narrow states retune the bar.
  • Reduced motion drops travel, scale, and blur and keeps short fades.
  • The root is a container; below collapseBelow (720px of its own width by default) the items fold into one menu.
  • Panels and search cap at the container width minus a gutter, and below 420px viewport width link panels drop to one column.
  • Hover-to-open only reacts to mouse pointers, so touch opens panels on tap without a hover flash.
  • The bar uses a 22px backdrop blur, which falls back to a solid surface under prefers-reduced-transparency and prefers-contrast.
  • Two ResizeObservers track the container and the open panel size; only the open panel is mounted.
  • Search ranks entries in memory on each keystroke and shows at most six results, so large indexes should be pre-filtered.

Notes for AI

Give your coding assistant the Markdown reference instead of screenshots.

  • Choose it for the top navigation of a marketing or product site with a handful of sections that each hold several destinations. Use tabs for in-page view switching and liquid-tab-bar for an app-style section switcher.
  • Pass current from the router and compact from a scroll listener. Route in onNavigate for client-side navigation; plain items and links with href also work as anchors.
/components/morph-nav/markdown

The full library index for assistants is at /llms.txt.