Navbar

A composable top navigation bar for marketing, product and ecommerce shells. Layout is composition, not configuration: a NavbarSpacer pushes groups apart. Collapses to a hamburger disclosure below md.

Installation#

# One-time setup (tokens + lib helpers)npx koalaui-cli@latest init# Add this component (its dependencies come along)npx koalaui-cli@latest add navbar

Usage#

usage.tsxTSX
import { Button } from "@/components/ui/button"import {  Navbar, NavbarInner, NavbarBrand, NavbarNav, NavbarLink, NavbarSpacer, NavbarActions,  NavbarMobileToggle, NavbarMobileMenu, NavbarMobileLink,} from "@/components/ui/navbar"export function Example() {  return (    <Navbar>      <NavbarInner>        <NavbarBrand href="/">Koala UI</NavbarBrand>        <NavbarNav>          <NavbarLink href="/">Home</NavbarLink>          <NavbarLink href="/features" active>Features</NavbarLink>          <NavbarLink href="/pricing">Pricing</NavbarLink>        </NavbarNav>        <NavbarSpacer />        <NavbarActions>          <Button size="sm" variant="outline">Sign in</Button>          <Button size="sm">Sign up</Button>        </NavbarActions>        <NavbarMobileToggle />      </NavbarInner>      <NavbarMobileMenu>        <NavbarMobileLink href="/">Home</NavbarMobileLink>        <NavbarMobileLink href="/features">Features</NavbarMobileLink>        <NavbarMobileLink href="/pricing">Pricing</NavbarMobileLink>      </NavbarMobileMenu>    </Navbar>  )}

Floating#

variant="floating" detaches the bar into a rounded card that hovers over the page. Give it top margin and a background to float over.

Floating island#

Release the width cap with w-fit max-w-none and the floating card stops stretching: it shrinks to its content and the recipe's own mx-auto centers it, so the whole bar becomes a compact pill hovering over the page. Best with a short link set and one CTA.

linkStyle changes what a link is, which is the one thing composition cannot express. The default, "pill", makes each link a ghost chip floating in the bar: bg-accent on hover in the light themes, a faint foreground/8 tint in the dark ones, where the accent would read as a heavy grey block. "underline" makes it a tab: the box fills the bar's full height so its indicator, a square 3px foreground stroke spanning the whole box, welds to the bar's bottom rule (ink, not brand: at full width it is already the loudest mark in the row). Hover previews that indicator in border instead of painting a full-height chip.

"text" makes each link a plain word: no chip, no stroke. Links rest in muted-foreground and light up to full ink on hover and while their menu is open, so the only thing that moves is the label's color. The current page is simply the link that stays lit. There is no press scale either, since a label that shrinks under the pointer reads as a glitch, and a page that is not live yet dims one step below its siblings.

A marketing bar that carries six links and two actions runs out of row long before the md breakpoint where the hamburger normally takes over, so on a tablet it would overflow or wrap. collapseAt="lg" moves the handover to 1024px: the inline nav, the toggle and the mobile panel switch together. A page that is not live yet renders as a <span aria-disabled> through asChild: muted, inert to the pointer, and paired with a small Badge.

Koala UI

Elevate on scroll#

elevateOnScroll rests the bar flat, borderless and shadowless, flush with the content, then brings its border and shadow in together the moment the page scrolls under it. Pair it with sticky top-0. The bar listens to the nearest scroll container, so it works on a page or inside a panel; scroll the preview to see it engage.

Alignment#

There is no alignment prop. A NavbarSpacer pushes the groups on either side of it apart, which pins the nav to the right. To truly center it, swap the bar for a three-column grid: spacers would only center the nav between the brand and the actions, leaving it off the bar's centreline by half the difference in their widths.

A link that opens a menu is a NavbarLink wrapped in the standard DropdownMenu. The caret flips when its menu opens.

Swap the click-triggered DropdownMenu for a NavigationMenu when the bar carries more than one dropdown link. It opens on hover, and every trigger shares one panel: moving from “Product” to “Resources” resizes it instead of swapping popovers.

Koala UI

NavbarSearch is the DS Input with a leading magnifier. Set a width like w-64 for a normal field, or flex-1 to fill the center of the bar. Add collapsible and it rests as one of the bar's icon chips instead, growing into the same field on click (an ExpandableSearch): the choice for a bar whose links need the room until someone searches.

Koala UI

Product app shell#

A compact bar with a global search and an account cluster. Pass bg-muted border-transparent to NavbarSearch for the pill look, and drop an Avatar into NavbarActions. To make it the header of a whole app, put it in a LayoutTopbar: it docks onto the shell and spans the window.

Toolbar#

Drop the brand and the links and the same parts become a toolbar: the view's controls on the left, its actions on the right. This is the bar that sits under an app shell's real header. Fold navigation back in and it takes the three-column grid, so controls, tabs, and account each hold their own third.

A

Logo in the middle#

A 3-column grid on NavbarInner centers the brand independently of the side groups: links left, logo centered, actions right.

Multiple actions#

Stack two quiet outline actions and a solid primary in NavbarActions for a stronger conversion path. Give the secondaries a hidden sm:inline-flex so they shed themselves as the bar narrows and the primary always survives.

Badge beside the brand#

Group a Badge next to NavbarBrand to flag a beta, plan, or environment.

Ecommerce#

The same parts build a storefront header, with two conventions of its own: the links go uppercase and wide-tracked, and the marketing CTAs give way to the search, account, and cart trio. Unlike a marketing CTA the trio stays in the bar at every width, because the cart is the one control a shopper must never have to go looking for. Both are composition, so no variant is involved: the brand can lead, or the catalogue can, with the mark on the centreline.

Density#

density tightens the bar height and gutters for application shells. Set it per navbar or for a whole subtree with DensityProvider. See Density.

API reference#

Navbar

The root <header>. Owns the mobile disclosure state and provides the styling context to every part. Forwards all <header> props.

  • variant: "full" (default) or "floating".
  • linkStyle: "pill" (default), "underline" or "text". Ghost chips floating in the bar, full-height tabs whose ink indicator welds to the bar's bottom rule, or plain muted words that light up to full ink on hover.
  • density: "comfortable" (default) or "compact". Falls back to the nearest DensityProvider.
  • collapseAt: "md" (default) or "lg". Where the inline links hand over to the hamburger. A bar carrying six links and two actions runs out of row well before 768px, so it collapses at 1024px instead of overflowing; the nav, the toggle and the mobile panel all move together.
  • docked: sit the bar on an app shell's surface instead of painting its own: no fill, no bottom rule, and a full-width row instead of the marketing column. Inherited inside a LayoutTopbar, so you rarely pass it; docked={false} keeps a bar's standalone chrome inside a shell.
  • open / defaultOpen / onOpenChange: control the mobile menu.

NavbarInner

The max-width content row. Holds the brand, nav, spacers, actions, and toggle.

NavbarBrand

The logo lockup; renders an <a>. Pass asChild to use a framework <Link>.

NavbarNav

The horizontal link list (a labelled <nav>); hidden below md.

NavbarLink

A link in the bar. active adds the style's indicator and aria-current="page"; asChild renders a custom element or a menu trigger. Its shape follows the bar's linkStyle: a ghost chip with a soft-capped underline, a full-height tab with a square one, or a plain word that stays lit. A page that is not live yet takes aria-disabled (render a <span> through asChild): the link goes muted and inert to the pointer. Pair it with a small Badge ("Soon"). NavbarMobileLink takes the same state.

NavbarSearch

The DS Input with a leading magnifier and a default width. Forwards InputRoot props (size, hasError…); inputProps reaches the underlying <input>. collapsible rests it as a 36px icon chip that expands into the field on click (an ExpandableSearch); it then takes open / defaultOpen / onOpenChange, and className sets the open width.

NavbarActions · NavbarSpacer

NavbarActions is the right-hand cluster; NavbarSpacer is a flexible gap that drives alignment.

NavbarMobileToggle · NavbarMobileMenu · NavbarMobileLink

The hamburger, the disclosed panel (mounts only while open), and its stacked links. All visible only below md.

FAQ#

Alignment is composition, not configuration: drop a `NavbarSpacer` between groups to push them apart. One spacer after the brand pins the nav right. For a truly centered nav, reach for `className="md:grid md:grid-cols-[1fr_auto_1fr]"` on `NavbarInner` instead: spacers only center the nav between its neighbours, so it drifts off the bar's centreline whenever the brand and the actions differ in width.