navbars /
Mega Dropdown Navbar
Top nav with a multi-column dropdown panel that opens on click; closes on outside click or ESC.
Preview
Source
tsx
"use client";
import { useEffect, useRef, useState } from "react";
import { Button } from "@/components/ui/button";
import { Sparkles, ChevronDown } from "lucide-react";
const megaColumns = [
{
heading: "Products",
items: [
{ label: "Analytics", desc: "Track and measure growth", href: "#" },
{ label: "Automation", desc: "Workflows that run themselves", href: "#" },
{ label: "Insights", desc: "AI-generated recommendations", href: "#" },
],
},
{
heading: "Solutions",
items: [
{ label: "For startups", desc: "Move fast from day one", href: "#" },
{ label: "For enterprise", desc: "Scale with confidence", href: "#" },
{ label: "For agencies", desc: "Manage clients at scale", href: "#" },
],
},
{
heading: "Resources",
items: [
{ label: "Docs", desc: "Guides and API reference", href: "#" },
{ label: "Blog", desc: "Product updates and essays", href: "#" },
{ label: "Community", desc: "Forums, Discord, events", href: "#" },
],
},
];
export default function NavbarMegaDropdown() {
const [open, setOpen] = useState(false);
const wrapperRef = useRef<HTMLDivElement>(null);
useEffect(() => {
if (!open) return;
const onClick = (e: MouseEvent) => {
if (wrapperRef.current && !wrapperRef.current.contains(e.target as Node)) {
setOpen(false);
}
};
const onKey = (e: KeyboardEvent) => {
if (e.key === "Escape") setOpen(false);
};
document.addEventListener("mousedown", onClick);
document.addEventListener("keydown", onKey);
return () => {
document.removeEventListener("mousedown", onClick);
document.removeEventListener("keydown", onKey);
};
}, [open]);
return (
<header className="w-full border-b border-border bg-background relative">
<div className="container mx-auto flex items-center justify-between gap-6 px-6 py-4">
<a href="#" className="flex items-center gap-2 text-foreground font-bold">
<Sparkles className="w-5 h-5 text-primary" />
<span>Acme</span>
</a>
<nav className="hidden md:flex items-center gap-6" ref={wrapperRef}>
<button
type="button"
onClick={() => setOpen((v) => !v)}
aria-expanded={open}
className="inline-flex items-center gap-1 text-sm text-muted-foreground hover:text-foreground transition-colors"
>
Explore
<ChevronDown className={`w-4 h-4 transition-transform ${open ? "rotate-180" : ""}`} />
</button>
<a href="#" className="text-sm text-muted-foreground hover:text-foreground transition-colors">Pricing</a>
<a href="#" className="text-sm text-muted-foreground hover:text-foreground transition-colors">Customers</a>
<a href="#" className="text-sm text-muted-foreground hover:text-foreground transition-colors">Company</a>
</nav>
<Button size="sm">Get started</Button>
</div>
{open && (
<div className="absolute left-0 right-0 top-full border-t border-border bg-background shadow-xl z-40">
<div className="container mx-auto grid grid-cols-1 md:grid-cols-3 gap-8 px-6 py-8">
{megaColumns.map((col) => (
<div key={col.heading}>
<h3 className="text-xs font-semibold uppercase tracking-widest text-muted-foreground mb-4">
{col.heading}
</h3>
<ul className="space-y-3">
{col.items.map((it) => (
<li key={it.label}>
<a
href={it.href}
className="block rounded-md p-2 -m-2 hover:bg-accent transition-colors"
>
<div className="text-sm font-medium text-foreground">{it.label}</div>
<div className="text-xs text-muted-foreground mt-0.5">{it.desc}</div>
</a>
</li>
))}
</ul>
</div>
))}
</div>
</div>
)}
</header>
);
} Claude Code Instructions
CLI Install
npx innovations add mega-dropdownWhere to use it
Use when your product has enough surface area to warrant grouping (multiple products, solutions, resources).
In Astro (src/layouts/Layout.astro):
import NavbarMegaDropdown from '../components/innovations/navbars/mega-dropdown';
Customize: edit the megaColumns array at the top. Each column has a heading and items with label + desc + href. You can add more columns — the grid will adapt (consider md:grid-cols-4 if you add a 4th).