A store bar with a wordmark, category triggers (Women, Men, Kids, Home) that each drop a full-width panel of four link columns beside a New in photo tile, and on the right an inline search input, an account icon and a bag icon with a count bubble. On phones a left drawer opens with the categories as tabs across its top. Every panel and tab content stays in the markup and is toggled with CSS.
A store bar with category triggers that each drop a full-width panel of four link columns beside a New in photo tile, an inline search input, an account icon and a bag icon with a count bubble, with a tabbed left drawer on phones.
Upgrade to Pro
Pro blocks install through the shadcn CLI with your license key and ship their full source. Docs and live previews stay open to everyone, so you can read every block's details first.
Swap YOUR_EMAIL and YOUR_KEY for the email and license key on your account. Find your license key on your account page.
Radix flavor
npx shadcn add "https://beste.dev/r/navbar91?email=YOUR_EMAIL&license_key=YOUR_KEY"Base UI flavor
npx shadcn add "https://beste.dev/r-base/navbar91?email=YOUR_EMAIL&license_key=YOUR_KEY"This installs the block to components/beste/block/navbar91.tsx plus the shadcn input primitive it uses.
The installed file exports navbar91Demo alongside the block: the exact props behind the preview above. Spread it to get a working navbar in one line.
import { Navbar91, navbar91Demo } from "@/components/beste/block/navbar91";
export default function Page() {
return <Navbar91 {...navbar91Demo} />;
}Then replace the demo with your own props. Written out, a trimmed setup looks like this:
import { Navbar91 } from "@/components/beste/block/navbar91";
export default function Page() {
return (
<Navbar91
brand="Harbor"
categories={[
{
label: "Women",
href: "/women",
columns: [
{
title: "Clothing",
links: [
{ label: "Dresses", href: "/women/dresses" },
{ label: "Knitwear", href: "/women/knitwear" },
],
},
{ title: "Shoes", links: [{ label: "Boots", href: "/women/boots" }] },
],
featured: {
eyebrow: "New in",
title: "The wool coat, back in four colours",
href: "/women/coats",
image: { src: "/photos/coat.jpg", alt: "A wool coat on a rail" },
},
},
{
label: "Men",
href: "/men",
columns: [{ title: "Clothing", links: [{ label: "Shirts", href: "/men/shirts" }] }],
featured: {
eyebrow: "New in",
title: "Field watches with a sapphire face",
href: "/men/watches",
image: { src: "/photos/watch.jpg", alt: "A field watch" },
},
},
]}
bagCount={3}
labels={{ search: "Search the store", account: "Account", bag: "Bag", open: "Open menu", close: "Close menu" }}
/>
);
}| Prop | Type | Default | Description |
|---|---|---|---|
brand | string | – | Wordmark on the left |
categories | Category[] | [] | Category triggers; one mega panel and one drawer tab each |
bagCount | number | – | Count shown in the bubble on the bag icon; hidden when 0 or unset |
labels | { search?: string; account?: string; bag?: string; open?: string; close?: string } | {} | Placeholder for the search input and accessible names for the icon buttons and the menu toggle |
className | string | – | Extra classes for the outer <header> |
type Category = {
label: string;
href: string;
columns: LinkGroup[];
featured: Featured;
};
type LinkGroup = {
title: string;
links: NavItem[];
};
type Featured = {
eyebrow: string;
title: string;
href: string;
image: { src: string; alt: string };
};
type NavItem = {
label: string;
href: string;
};invisible -translate-y-1 opacity-0 for visible translate-y-0 opacity-100, so every column link is in the HTML.aria-expanded and aria-controls pointing at their panel through a useId prefix.role="tab" buttons across its top; all four tab panels are mounted and the inactive ones are hidden with CSS, with aria-selected and aria-hidden kept in sync.inert while closed so its off-screen links are not keyboard-reachable, and a scrim closes it on tap; links inside it close it on click.bagCount is a number above zero.