# Responsive React Navbar with Mega Menu, Animated Hamburger and Sticky Shrink on Scroll

> Free responsive React navbar in Tailwind: mega menu, dropdown, animated hamburger, sticky bar that shrinks on scroll, active link and full keyboard support.

A shadcn/ui block from the [@weinc](https://we.inc/components?utm_source=shadcn.exchange) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/weinc/responsive-react-navbar-with-mega-menu-animated-hamburger-and-sticky-shrink-on-scroll).

- Page, with a live preview: https://shadcn.exchange/r/weinc/responsive-react-navbar-with-mega-menu-animated-hamburger-and-sticky-shrink-on-scroll
- Screenshot: https://shadcn.exchange/shot/weinc/responsive-react-navbar-with-mega-menu-animated-hamburger-and-sticky-shrink-on-scroll/light.png
- Registry item: https://we.inc/r/responsive-react-navbar-with-mega-menu-animated-hamburger-and-sticky-shrink-on-scroll.json
- Listed: 2026-10-28, source last changed 2026-10-28

## Install

```bash
npx shadcn@latest add https://shadcn.exchange/r/weinc/responsive-react-navbar-with-mega-menu-animated-hamburger-and-sticky-shrink-on-scroll.json
```

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

## Dependencies

- npm packages: `framer-motion`

## Files

### `components/we-inc/responsive-react-navbar-with-mega-menu-animated-hamburger-and-sticky-shrink-on-scroll.tsx`

```tsx
import { useEffect, useId, useRef, useState } from "react";
import type { KeyboardEvent, ReactNode, RefObject } from "react";
import { AnimatePresence, motion, useReducedMotion } from "framer-motion";

/* ---------- Edit the menu here: the desktop bar and the phone menu both read from it ---------- */
type Item = { label: string; text: string; icon: string };
type NavLink = { label: string; href: string; mega?: Item[]; menu?: Item[] };

const brand = "Larkspur";
const ACTIVE = "Pricing"; // the page you are on: gets aria-current="page"
const COMPACT_BELOW = 768; // the bar switches to the hamburger below this width (of its own box)

const links: NavLink[] = [
  {
    label: "Product",
    href: "#",
    mega: [
      { label: "Booking pages", text: "One link clients use to pick a free hour.", icon: "M4 5h16v15H4zM4 10h16M9 3v4M15 3v4" },
      { label: "Team calendars", text: "See every chair, room and person at once.", icon: "M4 6h16M4 12h16M4 18h10" },
      { label: "Reminders", text: "Texts and emails that cut no-shows.", icon: "M6 16V11a6 6 0 1 1 12 0v5l2 2H4zM10 21h4" },
      { label: "Payments", text: "Take deposits when the slot is booked.", icon: "M3 7h18v10H3zM3 11h18M7 15h3" },
      { label: "Reports", text: "Busy hours, repeat clients, takings.", icon: "M5 20V10M12 20V4M19 20v-7" },
      { label: "Integrations", text: "Sync with the calendar you already use.", icon: "M9 7h6v4H9zM12 11v4M6 15h12v5H6z" },
    ],
  },
  { label: "Pricing", href: "#" },
  { label: "Customers", href: "#" },
  {
    label: "Resources",
    href: "#",
    menu: [
      { label: "Help centre", text: "Guides for every setting.", icon: "M12 21a9 9 0 1 0 0-18 9 9 0 0 0 0 18zM9.5 9a2.5 2.5 0 1 1 3.5 2.3c-.6.3-1 .9-1 1.7M12 17h.01" },
      { label: "Changelog", text: "What shipped this month.", icon: "M5 4h14v16H5zM9 9h6M9 13h6" },
      { label: "Templates", text: "Ready booking pages by trade.", icon: "M4 4h7v7H4zM13 4h7v7h-7zM4 13h7v7H4zM13 13h7v7h-7z" },
    ],
  },
  { label: "Docs", href: "#" },
];

const variants = {
  light: { name: "Light", bar: "bg-white/95 text-slate-900 border-slate-200", link: "text-slate-600 hover:text-slate-900 hover:bg-slate-100", on: "text-slate-900", dot: "bg-emerald-600", cta: "bg-slate-900 text-white hover:bg-slate-700", ghost: "text-slate-700 hover:bg-slate-100", page: "bg-slate-50", ring: "focus-visible:ring-emerald-600 focus-visible:ring-offset-white" },
  dark: { name: "Dark", bar: "bg-[#0d1412]/95 text-white border-white/10", link: "text-slate-300 hover:text-white hover:bg-white/10", on: "text-white", dot: "bg-emerald-400", cta: "bg-emerald-400 text-[#0d1412] hover:bg-emerald-300", ghost: "text-slate-200 hover:bg-white/10", page: "bg-[#0a0f0e]", ring: "focus-visible:ring-emerald-400 focus-visible:ring-offset-[#0d1412]" },
  pill: { name: "Floating", bar: "bg-white/95 text-slate-900 border-slate-200", link: "text-slate-600 hover:text-slate-900 hover:bg-slate-100", on: "text-slate-900", dot: "bg-orange-500", cta: "bg-orange-600 text-white hover:bg-orange-700", ghost: "text-slate-700 hover:bg-slate-100", page: "bg-[#f4efe8]", ring: "focus-visible:ring-orange-600 focus-visible:ring-offset-white" },
} as const;
type VariantKey = keyof typeof variants;

/* ---------- Small hooks ---------- */
/** True once the scroll box (or the window when no ref is given) has moved past `offset`. */
function useScrolled(box?: RefObject<HTMLElement>, offset = 12) {
  const [scrolled, setScrolled] = useState(false);
  useEffect(() => {
    const el: HTMLElement | Window = box?.current ?? window;
    const read = () => setScrolled((box?.current ? box.current.scrollTop : window.scrollY) > offset);
    read();
    el.addEventListener("scroll", read, { passive: true });
    return () => el.removeEventListener("scroll", read);
  }, [box, offset]);
  return scrolled;
}

/** Width of the navbar's own box, so it is responsive inside any container. */
function useCompact(ref: RefObject<HTMLElement>) {
  const [compact, setCompact] = useState(false);
  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    const ro = new ResizeObserver(([e]) => setCompact(e.contentRect.width < COMPACT_BELOW));
    ro.observe(el);
    return () => ro.disconnect();
  }, [ref]);
  return compact;
}

function Icon({ d, className = "h-5 w-5" }: { d: string; className?: string }) {
  return (
    <svg viewBox="0 0 24 24" className={className} fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
      <path d={d} />
    </svg>
  );
}

function Logo({ dot }: { dot: string }) {
  return (
    <span className="flex items-center gap-2 font-semibold tracking-tight">
      <span className={`grid h-7 w-7 place-items-center rounded-lg ${dot}`}>
        <svg viewBox="0 0 16 16" className="h-4 w-4 text-white" fill="currentColor" aria-hidden="true"><path d="M8 2c2 2.5 2 4.5 0 6-2-1.5-2-3.5 0-6zM3 9c2.5-.5 4 .5 5 3-2.5.5-4-.5-5-3zm10 0c-1 2.5-2.5 3.5-5 3 1-2.5 2.5-3.5 5-3z" /></svg>
      </span>
      {brand}
    </span>
  );
}

/* ---------- The animated hamburger: three bars that fold into an X ---------- */
function Burger({ open, reduce }: { open: boolean; reduce: boolean }) {
  const t = reduce ? { duration: 0 } : { type: "spring", stiffness: 420, damping: 30 };
  return (
    <span className="relative block h-4 w-5" aria-hidden="true">
      <motion.span className="absolute left-0 top-0 h-0.5 w-5 rounded-full bg-current" animate={open ? { y: 7, rotate: 45 } : { y: 0, rotate: 0 }} transition={t} />
      <motion.span className="absolute left-0 top-[7px] h-0.5 w-5 rounded-full bg-current" animate={{ opacity: open ? 0 : 1, scaleX: open ? 0.2 : 1 }} transition={t} />
      <motion.span className="absolute left-0 top-[14px] h-0.5 w-5 rounded-full bg-current" animate={open ? { y: -7, rotate: -45 } : { y: 0, rotate: 0 }} transition={t} />
    </span>
  );
}

/* ---------- The navbar itself ---------- */
type NavbarProps = { variant: VariantKey; scrollBox?: RefObject<HTMLElement>; startOpen?: string | null; startMobileOpen?: boolean; forceScrolled?: boolean };

export function Navbar({ variant, scrollBox, startOpen = null, startMobileOpen = false, forceScrolled }: NavbarProps) {
  const v = variants[variant];
  const reduce = !!useReducedMotion();
  const root = useRef<HTMLElement>(null);
  const compact = useCompact(root);
  const scrolledLive = useScrolled(scrollBox);
  const scrolled = forceScrolled ?? scrolledLive;
  const [open, setOpen] = useState<string | null>(startOpen);
  const [mobile, setMobile] = useState(startMobileOpen);
  const [section, setSection] = useState<string | null>("Product");
  const uid = useId();
  const burgerRef = useRef<HTMLButtonElement>(null);
  const triggers = useRef<Record<string, HTMLButtonElement | null>>({});
  const ring = `focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 ${v.ring}`;
  const spring = reduce ? { duration: 0 } : { type: "spring", stiffness: 380, damping: 32 };

  useEffect(() => setOpen(startOpen), [startOpen]);
  // Close an open menu once the page has really scrolled (not on the tiny scroll a focus jump can cause).
  useEffect(() => {
    const box = scrollBox?.current;
    const top = () => (box ? box.scrollTop : window.scrollY);
    let start = top();
    const onScroll = () => { if (Math.abs(top() - start) > 48) { setOpen(null); start = top(); } };
    const target: HTMLElement | Window = box ?? window;
    target.addEventListener("scroll", onScroll, { passive: true });
    return () => target.removeEventListener("scroll", onScroll);
  }, [scrollBox, open]);
  useEffect(() => {
    const away = (e: PointerEvent) => { if (root.current && !root.current.contains(e.target as Node)) setOpen(null); };
    document.addEventListener("pointerdown", away);
    return () => document.removeEventListener("pointerdown", away);
  }, []);

  const onKey = (e: KeyboardEvent) => {
    if (e.key !== "Escape") return;
    if (open) { triggers.current[open]?.focus(); setOpen(null); }
    if (mobile) { setMobile(false); burgerRef.current?.focus(); }
  };
  const openWithArrow = (e: KeyboardEvent, label: string) => {
    if (e.key !== "ArrowDown") return;
    e.preventDefault();
    setOpen(label);
    requestAnimationFrame(() => document.getElementById(`${uid}-${label}`)?.querySelector("a")?.focus());
  };

  const pill = variant === "pill";
  const shell = pill
    ? `mx-auto mt-3 w-[calc(100%-1.5rem)] border ${mobile ? "rounded-3xl" : "rounded-full"} shadow-[0_8px_30px_-12px_rgba(15,23,42,0.25)] ${scrolled ? "max-w-4xl" : "max-w-5xl"}`
    : `w-full border-b ${scrolled ? "shadow-[0_6px_24px_-14px_rgba(0,0,0,0.35)]" : "border-transparent"}`;

  return (
    <header ref={root} onKeyDown={onKey} className="sticky top-0 z-30">
      <div className={`${shell} ${v.bar} backdrop-blur transition-all duration-300 motion-reduce:transition-none`}>
        <nav aria-label="Main" className={`mx-auto flex max-w-6xl items-center gap-2 px-4 transition-[padding] duration-300 motion-reduce:transition-none sm:px-5 ${scrolled ? "py-2" : pill ? "py-2.5" : "py-4"}`}>
          <a href="#" className={`mr-auto rounded-lg ${ring}`} aria-label={`${brand} home`}><Logo dot={v.dot} /></a>

          {!compact && (
            <ul className="flex items-center gap-1 text-[15px]">
              {links.map((l) => {
                const panel = l.mega ?? l.menu;
                const isOpen = open === l.label;
                const current = l.label === ACTIVE;
                if (!panel)
                  return (
                    <li key={l.label}>
                      <a href={l.href} aria-current={current ? "page" : undefined} className={`relative flex h-10 items-center rounded-full px-3.5 font-medium transition-colors ${current ? v.on : v.link} ${ring}`}>
                        {l.label}
                        {current && <span className={`absolute bottom-1 left-1/2 h-1 w-1 -translate-x-1/2 rounded-full ${v.dot}`} aria-hidden="true" />}
                      </a>
                    </li>
                  );
                return (
                  <li key={l.label} className={l.mega ? "" : "relative"}>
                    <button
                      ref={(el) => { triggers.current[l.label] = el; }}
                      type="button"
                      aria-expanded={isOpen}
                      aria-controls={`${uid}-${l.label}`}
                      onClick={() => setOpen(isOpen ? null : l.label)}
                      onKeyDown={(e) => openWithArrow(e, l.label)}
                      className={`flex h-10 items-center gap-1 rounded-full px-3.5 font-medium transition-colors ${isOpen ? `${v.on} ${variant === "dark" ? "bg-white/10" : "bg-slate-100"}` : v.link} ${ring}`}
                    >
                      {l.label}
                      <motion.svg viewBox="0 0 16 16" className="h-3.5 w-3.5" animate={{ rotate: isOpen ? 180 : 0 }} transition={spring} fill="none" stroke="currentColor" strokeWidth="2" aria-hidden="true"><path d="M4 6l4 4 4-4" /></motion.svg>
                    </button>
                    <AnimatePresence>
                      {isOpen && (
                        <motion.div
                          id={`${uid}-${l.label}`}
                          initial={{ opacity: 0, y: -8, scale: 0.98 }}
                          animate={{ opacity: 1, y: 0, scale: 1 }}
                          exit={{ opacity: 0, y: -6, scale: 0.98 }}
                          transition={reduce ? { duration: 0 } : { type: "spring", stiffness: 460, damping: 34 }}
                          className={`absolute z-40 mt-2 origin-top rounded-2xl border p-2 shadow-[0_24px_60px_-20px_rgba(15,23,42,0.35)] ${variant === "dark" ? "border-white/10 bg-[#121a18] text-white" : "border-slate-200 bg-white text-slate-900"} ${l.mega ? "left-3 right-3 mx-auto max-w-[760px]" : "right-0 w-72"}`}
                        >
                          {l.mega ? <Mega items={l.mega} dark={variant === "dark"} ring={ring} dot={v.dot} /> : <List items={panel} dark={variant === "dark"} ring={ring} />}
                        </motion.div>
                      )}
                    </AnimatePresence>
                  </li>
                );
              })}
            </ul>
          )}

          <div className="ml-auto flex items-center gap-1.5">
            {!compact && <a href="#" className={`flex h-10 items-center whitespace-nowrap rounded-full px-3.5 text-[15px] font-medium ${v.ghost} ${ring}`}>Sign in</a>}
            <a href="#" className={`flex h-10 items-center whitespace-nowrap rounded-full px-4 text-[15px] font-semibold transition-colors ${v.cta} ${ring}`}>Start free</a>
            {compact && (
              <button ref={burgerRef} type="button" aria-expanded={mobile} aria-controls={`${uid}-mobile`} aria-label={mobile ? "Close menu" : "Open menu"} onClick={() => setMobile((m) => !m)} className={`grid h-10 w-10 place-items-center rounded-full ${v.ghost} ${ring}`}>
                <Burger open={mobile} reduce={reduce} />
              </button>
            )}
          </div>
        </nav>

        <AnimatePresence initial={false}>
          {compact && mobile && (
            <motion.div id={`${uid}-mobile`} initial={{ height: 0, opacity: 0 }} animate={{ height: "auto", opacity: 1 }} exit={{ height: 0, opacity: 0 }} transition={reduce ? { duration: 0 } : { type: "spring", stiffness: 300, damping: 34 }} className="overflow-hidden">
              <ul className={`space-y-0.5 px-3 pb-4 pt-1 text-[15px] ${pill ? "rounded-b-3xl" : ""}`}>
                {links.map((l, i) => {
                  const panel = l.mega ?? l.menu;
                  const expanded = section === l.label;
                  return (
                    <motion.li key={l.label} initial={{ opacity: 0, y: -6 }} animate={{ opacity: 1, y: 0 }} transition={reduce ? { duration: 0 } : { delay: 0.04 * i }}>
                      {panel ? (
                        <>
                          <button type="button" aria-expanded={expanded} onClick={() => setSection(expanded ? null : l.label)} className={`flex h-11 w-full items-center justify-between rounded-xl px-3 font-medium ${v.ghost} ${ring}`}>
                            {l.label}
                            <motion.svg viewBox="0 0 16 16" className="h-4 w-4" animate={{ rotate: expanded ? 180 : 0 }} transition={spring} fill="none" stroke="currentColor" strokeWidth="2" aria-hidden="true"><path d="M4 6l4 4 4-4" /></motion.svg>
                          </button>
                          <AnimatePresence initial={false}>
                            {expanded && (
                              <motion.ul initial={{ height: 0 }} animate={{ height: "auto" }} exit={{ height: 0 }} transition={spring} className="overflow-hidden pl-3">
                                {panel.slice(0, 4).map((it) => (
                                  <li key={it.label}>
                                    <a href="#" className={`flex h-10 items-center gap-2.5 rounded-lg px-3 text-[14px] ${v.link} ${ring}`}><Icon d={it.icon} className="h-4 w-4" />{it.label}</a>
                                  </li>
                                ))}
                              </motion.ul>
                            )}
                          </AnimatePresence>
                        </>
                      ) : (
                        <a href={l.href} aria-current={l.label === ACTIVE ? "page" : undefined} className={`flex h-11 items-center justify-between rounded-xl px-3 font-medium ${l.label === ACTIVE ? v.on : v.ghost} ${ring}`}>
                          {l.label}
                          {l.label === ACTIVE && <span className={`h-1.5 w-1.5 rounded-full ${v.dot}`} aria-hidden="true" />}
                        </a>
                      )}
                    </motion.li>
                  );
                })}
                <li className={`mt-2 border-t pt-3 ${variant === "dark" ? "border-white/10" : "border-slate-200"}`}>
                  <a href="#" className={`flex h-11 items-center justify-center rounded-full border text-[15px] font-medium ${variant === "dark" ? "border-white/15" : "border-slate-300"} ${v.ghost} ${ring}`}>Sign in</a>
                </li>
              </ul>
            </motion.div>
          )}
        </AnimatePresence>
      </div>
    </header>
  );
}

function Mega({ items, dark, ring, dot }: { items: Item[]; dark: boolean; ring: string; dot: string }) {
  return (
    <div className="grid gap-2 md:grid-cols-[1fr_220px]">
      <ul className="grid gap-1 sm:grid-cols-2">
        {items.map((it) => (
          <li key={it.label}>
            <a href="#" className={`group flex gap-3 rounded-xl p-3 transition-colors ${dark ? "hover:bg-white/5" : "hover:bg-slate-50"} ${ring}`}>
              <span className={`grid h-9 w-9 shrink-0 place-items-center rounded-lg border ${dark ? "border-white/10 bg-white/5 text-emerald-300" : "border-slate-200 bg-white text-slate-700 group-hover:text-emerald-700"}`}><Icon d={it.icon} className="h-[18px] w-[18px]" /></span>
              <span>
                <span className="block text-[14px] font-semibold">{it.label}</span>
                <span className={`block text-[13px] leading-snug ${dark ? "text-slate-400" : "text-slate-600"}`}>{it.text}</span>
              </span>
            </a>
          </li>
        ))}
      </ul>
      <a href="#" className={`flex flex-col justify-between rounded-xl p-4 ${dark ? "bg-emerald-400/10" : "bg-slate-900 text-white"} ${ring}`}>
        <span className={`inline-flex w-fit items-center gap-1.5 rounded-full px-2 py-0.5 text-[11px] font-semibold uppercase tracking-wider ${dark ? "bg-emerald-400/15 text-emerald-300" : "bg-white/10 text-white"}`}><span className={`h-1.5 w-1.5 rounded-full ${dot}`} aria-hidden="true" />New</span>
        <span className="mt-4 grid grid-cols-5 gap-1" aria-hidden="true">
          {Array.from({ length: 15 }, (_, i) => (
            <span key={i} className={`h-4 rounded ${[2, 6, 11].includes(i) ? (dark ? "bg-emerald-400/70" : "bg-emerald-400") : [4, 8].includes(i) ? (dark ? "bg-white/25" : "bg-white/30") : dark ? "bg-white/10" : "bg-white/10"}`} />
          ))}
        </span>
        <span className="mt-4 block">
          <span className="block text-[15px] font-semibold leading-snug">Waitlists that fill cancelled slots for you</span>
          <span className={`mt-1 block text-[13px] ${dark ? "text-slate-300" : "text-slate-300"}`}>See how it works</span>
        </span>
      </a>
    </div>
  );
}

function List({ items, dark, ring }: { items: Item[]; dark: boolean; ring: string }) {
  return (
    <ul>
      {items.map((it) => (
        <li key={it.label}>
          <a href="#" className={`flex items-start gap-3 rounded-xl p-3 ${dark ? "hover:bg-white/5" : "hover:bg-slate-50"} ${ring}`}>
            <Icon d={it.icon} className={`mt-0.5 h-[18px] w-[18px] ${dark ? "text-emerald-300" : "text-slate-500"}`} />
            <span>
              <span className="block text-[14px] font-semibold">{it.label}</span>
              <span className={`block text-[13px] ${dark ? "text-slate-400" : "text-slate-600"}`}>{it.text}</span>
            </span>
          </a>
        </li>
      ))}
    </ul>
  );
}

/* ---------- Preview: desktop page on the left, phone with the menu open on the right ---------- */
function FakePage({ dark }: { dark: boolean }) {
  const line = dark ? "bg-white/10" : "bg-slate-200";
  return (
    <div className="mx-auto max-w-5xl px-6 pb-40 pt-16">
      <p className={`text-[13px] font-semibold uppercase tracking-wider ${dark ? "text-emerald-300" : "text-slate-500"}`}>Pricing</p>
      <h2 className={`mt-2 max-w-md text-3xl font-semibold tracking-tight ${dark ? "text-white" : "text-slate-900"}`}>One price per chair, every feature included.</h2>
      <div className="mt-8 grid gap-3 sm:grid-cols-3">
        {[["Solo", "$19"], ["Studio", "$15"], ["Salon", "$12"]].map(([plan, price]) => (
          <div key={plan} className={`h-40 rounded-2xl border p-4 ${dark ? "border-white/10 bg-white/[0.03] text-white" : "border-slate-200 bg-white text-slate-900"}`}>
            <p className={`text-[13px] font-medium ${dark ? "text-slate-400" : "text-slate-500"}`}>{plan}</p>
            <p className="mt-1 text-2xl font-semibold tracking-tight">{price}<span className={`text-[13px] font-normal ${dark ? "text-slate-400" : "text-slate-500"}`}> / chair / month</span></p>
            <div className={`mt-4 h-px ${line}`} />
          </div>
        ))}
      </div>
      <img src="https://images.pexels.com/photos/10318038/pexels-photo-10318038.jpeg?auto=compress&cs=tinysrgb&w=1200" alt="Hairdresser styling a client's hair in a bright salon" width={1200} height={800} loading="lazy" className="mt-8 aspect-[16/7] h-auto w-full rounded-2xl object-cover" />
    </div>
  );
}

function Frame({ label, children, className = "" }: { label: string; children: ReactNode; className?: string }) {
  return (
    <figure className={`flex min-w-0 flex-col ${className}`}>
      <figcaption className="mb-2 text-[12px] font-medium uppercase tracking-wider text-slate-600">{label}</figcaption>
      {children}
    </figure>
  );
}

export default function ResponsiveReactNavbar() {
  const [variant, setVariant] = useState<VariantKey>("light");
  const [demoOpen, setDemoOpen] = useState<string | null>("Product");
  const desk = useRef<HTMLDivElement>(null);
  const reduce = useReducedMotion();
  const [touched, setTouched] = useState(false); // any click or key press ends the self-playing demo
  const dark = variant === "dark";

  // Idle demo: show the mega menu, then scroll the page so the bar shrinks. Stops on any input.
  useEffect(() => {
    const box = desk.current;
    if (reduce || touched) return;
    const t = window.setTimeout(() => { setDemoOpen(null); box?.scrollTo({ top: 160, behavior: "smooth" }); }, 2200);
    return () => window.clearTimeout(t);
  }, [reduce, touched]);

  return (
    <div onPointerDownCapture={() => setTouched(true)} onKeyDownCapture={() => setTouched(true)} className="min-h-[640px] bg-[#eef0ec] px-4 py-8 font-['Inter_Tight','Inter',ui-sans-serif,system-ui] sm:px-8">
      <div className="mx-auto max-w-[1200px]">
        <div role="radiogroup" aria-label="Navbar style" className="mb-5 inline-flex rounded-full border border-slate-300 bg-white p-1">
          {(Object.keys(variants) as VariantKey[]).map((k) => (
            <button key={k} type="button" role="radio" aria-checked={variant === k} onClick={() => setVariant(k)} className={`h-9 rounded-full px-4 text-[14px] font-medium transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-slate-900 ${variant === k ? "bg-slate-900 text-white" : "text-slate-700 hover:bg-slate-100"}`}>
              {variants[k].name}
            </button>
          ))}
        </div>
        <div className="grid gap-6 lg:grid-cols-[minmax(0,1fr)_340px]">
          <Frame label="Sticky bar: scroll inside to see it shrink">
            <div ref={desk} className={`relative h-[480px] overflow-y-auto rounded-2xl border border-slate-300 ${variants[variant].page}`}>
              <Navbar key={variant} variant={variant} scrollBox={desk} startOpen={demoOpen} />
              <FakePage dark={dark} />
            </div>
          </Frame>
          <Frame label="Phone, menu open" className="hidden sm:flex">
            <div className={`relative h-[480px] w-full overflow-hidden rounded-[28px] border-[6px] border-slate-900 ${variants[variant].page}`}>
              <Navbar key={variant} variant={variant} startMobileOpen forceScrolled={false} />
              <FakePage dark={dark} />
            </div>
          </Frame>
        </div>
      </div>
    </div>
  );
}
```
