# Morph Search: Nav Bar

> A search button in a site header. It grows into a field with popular pages underneath; pick one to go there.

A shadcn/ui block from the [@keyframeui](https://keyframeui.com) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/keyframeui/morph-search-demo).

- Page, with a live preview: https://shadcn.exchange/r/keyframeui/morph-search-demo
- Screenshot: https://abzjhwgwpdpz7ua5.public.blob.vercel-storage.com/shots/keyframeui/morph-search-demo-light-8d57f8de7adba1ae.png
- Registry item: https://keyframeui.com/r/morph-search-demo.json
- Categories: search, command-menu, motion
- Listed: 2026-10-14, source last changed 2026-10-15

## Install

```bash
npx shadcn@latest add https://keyframeui.com/r/morph-search-demo.json
```

Run it in a project that has shadcn/ui set up. It adds the files below and installs what they depend on.

## Dependencies

- Registry items: `https://keyframeui.com/r/morph-search.json`

## Notes from the registry

Live preview, examples and props: https://keyframeui.com/components/morph-search#morph-search-demo

## Files

### `registry/demos/morph-search-demo.tsx`

```tsx
"use client";

import * as React from "react";
import { motion, useReducedMotion } from "motion/react";

import { MorphSearch, type MorphSearchItem } from "@/components/ui/morph-search";

const glyph = (d: string) => (
  <svg aria-hidden viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={1.75} strokeLinecap="round" strokeLinejoin="round">
    <path d={d} />
  </svg>
);

const pages: MorphSearchItem[] = [
  { id: "pricing", group: "Pages", label: "Pricing", description: "Plans for every team", icon: glyph("M20.6 13.4l-7.2 7.2a2 2 0 0 1-2.8 0L3 13V3h10l7.6 7.6a2 2 0 0 1 0 2.8ZM7.5 7.5h.01"), keywords: ["plans", "cost"] },
  { id: "changelog", group: "Pages", label: "Changelog", description: "What shipped this week", icon: glyph("M12 3l1.9 5.1L19 10l-5.1 1.9L12 17l-1.9-5.1L5 10l5.1-1.9Z"), keywords: ["updates", "release"] },
  { id: "customers", group: "Pages", label: "Customers", description: "Stories from teams like yours", icon: glyph("M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2M9 11a4 4 0 1 0 0-8 4 4 0 0 0 0 8M22 21v-2a4 4 0 0 0-3-3.9M16 3.1a4 4 0 0 1 0 7.8") },
  { id: "careers", group: "Pages", label: "Careers", description: "We're hiring", icon: glyph("M3 7h18v13H3zM8 7V4h8v3M3 13h18"), keywords: ["jobs"] },
  { id: "analytics", group: "Products", label: "Analytics", description: "Every event, in real time", icon: glyph("M3 3v18h18M7 14l4-4 3 3 6-6") },
  { id: "payments", group: "Products", label: "Payments", description: "Cards, wallets and payouts", icon: glyph("M2 6h20v12H2zM2 10h20M6 15h4"), keywords: ["billing", "checkout"] },
  { id: "identity", group: "Products", label: "Identity", description: "Sign-in that just works", icon: glyph("M12 3l8 3v6c0 5-3.5 8-8 9-4.5-1-8-4-8-9V6z"), keywords: ["auth", "login", "sso"] },
  { id: "storage", group: "Products", label: "Storage", description: "Files at the edge", icon: glyph("M4 6c0-1.7 3.6-3 8-3s8 1.3 8 3-3.6 3-8 3-8-1.3-8-3ZM4 6v12c0 1.7 3.6 3 8 3s8-1.3 8-3V6M4 12c0 1.7 3.6 3 8 3s8-1.3 8-3") },
  { id: "sales", group: "Help", label: "Contact sales", description: "Talk to a human", icon: glyph("M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2Z"), keywords: ["enterprise"] },
  { id: "status", group: "Help", label: "System status", description: "All systems normal", icon: glyph("M22 12h-4l-3 9L9 3l-3 9H2"), keywords: ["uptime", "outage"] },
];

const popular = ["pricing", "analytics", "changelog", "sales"].map((id) => ({
  ...pages.find((page) => page.id === id)!,
  group: "Popular",
}));

export function MorphSearchDemo() {
  const [page, setPage] = React.useState(pages[0]);
  const reduceMotion = useReducedMotion();

  return (
    <div className="w-full max-w-2xl overflow-hidden rounded-xl border border-zinc-200 bg-white dark:border-zinc-800 dark:bg-zinc-950">
      <header className="flex h-14 items-center gap-6 border-b border-zinc-200/80 px-4 dark:border-zinc-800/80">
        <span className="flex items-center gap-2 text-sm font-semibold text-zinc-900 dark:text-zinc-50">
          <span aria-hidden className="size-5 rounded-md bg-zinc-900 dark:bg-zinc-100" />
          Northwind
        </span>
        <nav className="hidden gap-5 text-sm text-zinc-500 sm:flex">
          {["Products", "Pricing", "Customers", "Docs"].map((link) => (
            <span key={link}>{link}</span>
          ))}
        </nav>
        <div className="ml-auto flex items-center gap-3">
          <MorphSearch
            items={pages}
            suggestions={popular}
            placeholder="Search Northwind…"
            onSelect={(item) => setPage(item)}
          />
          <span aria-hidden className="size-8 rounded-full bg-linear-to-br from-amber-300 to-rose-400" />
        </div>
      </header>

      <motion.main
        key={page.id}
        initial={{ opacity: 0, y: reduceMotion ? 0 : 6 }}
        animate={{ opacity: 1, y: 0 }}
        transition={{ duration: 0.3, ease: "easeOut" }}
        className="px-6 pt-12 pb-16"
      >
        <p className="font-mono text-xs uppercase tracking-widest text-zinc-500">{page.group}</p>
        <h2 className="mt-3 text-3xl font-semibold tracking-tight text-zinc-900 dark:text-zinc-50">
          {page.label}
        </h2>
        <p className="mt-2 max-w-sm text-sm leading-relaxed text-zinc-500">{page.description}.</p>
        <div className="mt-8 grid grid-cols-3 gap-3">
          {[0, 1, 2].map((block) => (
            <span key={block} className="h-16 rounded-lg bg-zinc-100 dark:bg-zinc-900" />
          ))}
        </div>
      </motion.main>
    </div>
  );
}
```
