Skip to content
All Taste components

Navigation

Top navbar

The bar across the top of an app or site, with the logo, main links and account actions.

app · marketing · collapses to a menu button when narrow

"use client";
import { useState } from "react";
import { Bell, Menu, Search, X } from "lucide-react";
import { cn } from "@/lib/utils";

const links = [
  { href: "/dashboard", label: "Dashboard" },
  { href: "/invoices", label: "Invoices" },
  { href: "/customers", label: "Customers" },
  { href: "/reports", label: "Reports" },
];

export function Navbar({ current = "/dashboard" }: { current?: string }) {
  const [open, setOpen] = useState(false);
  return (
    <header className="rounded-lg border border-border bg-bg">
      <div className="flex h-14 items-center gap-4 pl-4 pr-3">
        <a href="/" className="flex shrink-0 items-center gap-2 text-[14.5px] font-semibold tracking-tight text-fg">
          <span className="grid size-[22px] place-items-center rounded-sm bg-primary text-xs text-primary-fg">L</span>
          Ledgerline
        </a>
        <nav aria-label="Main" className="hidden gap-0.5 md:flex">
          {links.map((l) => (
            <a
              key={l.href}
              href={l.href}
              aria-current={current === l.href ? "page" : undefined}
              className="inline-flex h-8 items-center rounded px-2.5 text-[13.5px] font-medium text-fg-muted transition hover:bg-surface hover:text-fg aria-[current=page]:bg-surface-2 aria-[current=page]:text-fg"
            >
              {l.label}
            </a>
          ))}
        </nav>
        <div className="ml-auto flex items-center gap-1">
          <IconButton label="Search"><Search /></IconButton>
          <IconButton label="Notifications, 2 unread">
            <Bell />
            <span className="absolute right-2 top-[7px] size-[7px] rounded-full bg-danger ring-2 ring-bg" />
          </IconButton>
          <IconButton label={open ? "Close menu" : "Open menu"} className="md:hidden" aria-expanded={open} onClick={() => setOpen(!open)}>
            {open ? <X /> : <Menu />}
          </IconButton>
          <span className="ml-1 grid size-7 place-items-center rounded-full bg-primary-soft text-[11px] font-medium text-primary-soft-fg">AK</span>
        </div>
      </div>
      {open && (
        <nav aria-label="Main" className="grid gap-0.5 border-t border-border p-2 md:hidden">
          {links.map((l) => (
            <a key={l.href} href={l.href} aria-current={current === l.href ? "page" : undefined}
              className="rounded px-2.5 py-2 text-sm font-medium text-fg-muted hover:bg-surface aria-[current=page]:bg-surface-2 aria-[current=page]:text-fg">
              {l.label}
            </a>
          ))}
        </nav>
      )}
    </header>
  );
}

function IconButton({ label, className, children, ...props }:
  React.ButtonHTMLAttributes<HTMLButtonElement> & { label: string }) {
  return (
    <button
      type="button"
      aria-label={label}
      className={cn("relative grid size-8 place-items-center rounded text-fg-muted transition hover:bg-surface-2 hover:text-fg [&_svg]:size-4", className)}
      {...props}
    >
      {children}
    </button>
  );
}

The code uses the Taste Tailwind preset. Make yours on the Taste page with Export my system.