A fixed left rail of icon buttons with the brand mark on top and a create button at the bottom, beside a demo app content area. Hovering, focusing or clicking a rail item opens a flyout card to its right with a heading and described links. On a phone a top bar with the brand and a hamburger opens a fullscreen grid of icon tiles. The flyouts and the phone menu stay in the markup and are toggled with CSS.
An app-style navigation: a fixed left rail of icon buttons with the brand mark on top and a create button at the bottom, next to a demo content area. Each rail item opens a flyout card to its right with a heading and described links; on a phone a top bar with the brand and a hamburger opens a fullscreen grid of icon tiles.
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/navbar87?email=YOUR_EMAIL&license_key=YOUR_KEY"Base UI flavor
npx shadcn add "https://beste.dev/r-base/navbar87?email=YOUR_EMAIL&license_key=YOUR_KEY"This installs the block to components/beste/block/navbar87.tsx plus the shadcn button primitive it uses.
The installed file exports navbar87Demo alongside the block: the exact props behind the preview above. Spread it to get a working navbar in one line.
import { Navbar87, navbar87Demo } from "@/components/beste/block/navbar87";
export default function Page() {
return <Navbar87 {...navbar87Demo} />;
}Then replace the demo with your own props. Written out, a trimmed setup looks like this:
import { Navbar87 } from "@/components/beste/block/navbar87";
export default function Page() {
return (
<Navbar87
brand="Orbit"
items={[
{
icon: "folder",
label: "Projects",
href: "/projects",
heading: "Projects",
links: [
{ title: "All projects", description: "Every board you can open.", href: "/projects" },
{ title: "Starred", description: "The ones you pinned.", href: "/projects/starred" },
],
},
{
icon: "inbox",
label: "Inbox",
href: "/inbox",
heading: "Inbox",
links: [{ title: "Mentions", description: "Comments that name you.", href: "/inbox/mentions" }],
},
]}
button={{ label: "New project", href: "/projects/new" }}
labels={{ open: "Open menu", close: "Close menu", home: "Home" }}
/>
);
}Leave content out in a real app and render your page as a sibling with md:pl-16, so it clears the rail.
| Prop | Type | Default | Description |
|---|---|---|---|
brand | string | – | Brand name; its first letter becomes the mark on top of the rail |
items | RailItem[] | [] | Rail buttons, each with its own flyout and mobile tile |
button | ActionButton | – | Create button at the bottom of the rail and the foot of the mobile grid |
content | DemoContent | – | Demo content area rendered beside the rail |
labels | { open?: string; close?: string; home?: string } | {} | Accessible names for the mobile toggle, the close button and the brand mark |
className | string | – | Extra classes for the outer wrapper |
type RailItem = {
icon: IconName;
label: string;
href: string;
heading: string;
links: FlyoutLink[];
};
type FlyoutLink = {
title: string;
description: string;
href: string;
};
type IconName = "folder" | "inbox" | "chart" | "users" | "settings";
type ActionButton = {
label: string;
href: string;
};
type DemoContent = {
heading: string;
description: string;
cards: { title: string; description: string }[];
};aria-hidden and inert, which keeps their links out of the tab order.aria-expanded and aria-controls; flyouts close when the pointer leaves the rail, when focus moves out of it, on Escape and on a pointer down outside it.