Search-Expand Navigation Bar
moumenlab/search-expand-navFreeComponent
A nav bar that expands into a search field then grows into a recent-searches card.
Live preview
live · rendered by the registry
Rendered by moumenlab on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://lab.moumen.dev/r/search-expand-nav.jsonSource
1"use client";23import { useEffect, useId, useLayoutEffect, useRef, useState, type ReactNode } from "react";4import { MotionConfig, motion } from "motion/react";56// Search-expand navigation bar - a two-stage morph disclosure.7//8// Rest: a rounded bar with page icons + an avatar on the left and a search icon9// pinned right. Click search and it plays in two stages, each animating a10// single driving property:11//12// 1. Horizontal morph (open): the search icon GLIDES left to become the13// field's leading icon while the icons + avatar fade out, the input fades14// in, and a ✕ fades in on the right. The travel distance is measured from15// layout (offsetLeft - transform-independent), so it stays correct as the16// component shrinks on narrow screens.17// 2. Vertical grow (expanded): the box - anchored to the bottom - grows18// UPWARD (motion animates the panel's height to auto), turning the19// rectangle into a card with a recent-searches panel cascading in above.20//21// The stages are sequenced in JS (open → grow; collapse → un-morph). "flip"22// effect: the first icon rises + blurs into the search icon instead of the23// right one travelling. Animation via motion/react; honours24// prefers-reduced-motion. Requires the lab-theme tokens. Fully Tailwind.2526const MORPH_MS = 400;27const GROW_MS = 420;28const EASE = [0.22, 1, 0.36, 1] as const;29const SLIDE_EASE = [0.76, 0, 0.24, 1] as const; // icon crossing: symmetric, smooth30const MORPH = { duration: 0.4, ease: EASE } as const;31const GROW = { duration: 0.44, ease: EASE } as const;3233// Resting chrome fade: out with a small drift + blur, back in clean.34const CHROME_SHOWN = { opacity: 1, x: 0, scale: 1, filter: "blur(0px)" };35const CHROME_HIDDEN = { opacity: 0, x: -6.4, scale: 0.96, filter: "blur(3px)" };3637const ICON_BTN =38 "flex-none grid place-items-center w-[var(--nav-icon)] h-[var(--nav-icon)] rounded-[0.625rem] text-muted-foreground hover:bg-accent hover:text-foreground active:scale-[0.96] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring";3940const MENU_ITEM =41 "flex items-center gap-2.5 w-full px-2 py-2 rounded-lg text-foreground/80 text-sm text-left [transition:background-color_150ms_ease,color_150ms_ease] hover:bg-accent hover:text-foreground focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-ring";4243export interface NavItem {44 label: string;45 icon: ReactNode;46}4748export default function SearchExpandNav({49// … truncated
What it pulls in
npm packages
Other registry items
Files it writes
More from moumenlab
All 14 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Caret-Anchored Mention Popovercaret-mention-popover | moumenlab | Components | Free | 1 dep | |
| Command Palette with Argument Chipscommand-palette | moumenlab | Components | Free | 1 dep | |
| Drag-to-Reorder Listdrag-to-reorder-list | moumenlab | Components | Free | 1 dep | |
| File Upload Staging Areafile-upload-staging | moumenlab | Components | Free | 1 dep | |
| Hover-Expand Icon Striphover-expand-icon-strip | moumenlab | Components | Free | 1 dep | |
| Inertial Wheel Listinertial-wheel-list | moumenlab | Components | Free | 1 dep | |
| Morphing Checkout Flowmorphing-checkout | moumenlab | Components | Free | 1 dep | |
| OTP Segmented Inputotp-segmented-input | moumenlab | Components | Free | 1 dep |
