Navbar

Navbar 02 — Classic Top Bar

Full-width sticky top bar with blur, logo left, centered links, ghost and primary CTAs and a mobile dropdown menu.

$ npx shadcn@latest add @ludusvibe/navbar-02
Open in v0

Code

Installed to components/sections/navbar-02.tsx — it's yours to edit.

"use client"

import * as React from "react"
import { motion } from "motion/react"
import { Menu, X } from "lucide-react"

import { buttonVariants } from "@/components/ui/button"
import { fadeUp } from "@/lib/motion"
import { cn } from "@/lib/utils"

type NavLink = { label: string; href: string }
type Cta = { label: string; href: string }

export type Navbar02Props = {
  /** Text logo — pass a string or any node. */
  logo?: React.ReactNode
  logoHref?: string
  links?: NavLink[]
  /** Ghost-styled link, e.g. sign in. */
  secondaryCta?: Cta
  /** Primary button-styled link. */
  primaryCta?: Cta
  className?: string
}

export function Navbar02({
  logo = "Lumen",
  logoHref = "#",
  links = [
    { label: "Product", href: "#product" },
    { label: "Customers", href: "#customers" },
    { label: "Pricing", href: "#pricing" },
    { label: "Docs", href: "#docs" },
    { label: "Blog", href: "#blog" },
  ],
  secondaryCta = { label: "Sign in", href: "#" },
  primaryCta = { label: "Start free trial", href: "#" },
  className,
}: Navbar02Props) {
  const [open, setOpen] = React.useState(false)
  const panelId = React.useId()

  return (
    <header
      className={cn(
        "sticky top-0 z-50 w-full border-b bg-background/80 backdrop-blur-md",
        className
      )}
    >
      <nav
        aria-label="Main"
        className="relative mx-auto flex h-16 max-w-6xl items-center justify-between px-6"
      >
        <a
          href={logoHref}
          className="flex items-center gap-2.5 font-heading text-lg font-semibold tracking-tight"
        >
          <span
            aria-hidden
            className="grid size-6 place-items-center rounded-md bg-primary/10 ring-1 ring-primary/25"
          >
            <span className="size-2.5 rounded-sm bg-primary" />
          </span>
          {logo}
        </a>

        <div className="absolute top-1/2 left-1/2 hidden -translate-x-1/2 -translate-y-1/2 items-center gap-1 md:flex">
          {links.map((link) => (
            <a
              key={link.label}
              href={link.href}
              className="rounded-lg px-3 py-1.5 text-sm text-muted-foreground transition-colors hover:bg-muted hover:text-foreground"
            >
              {link.label}
            </a>
          ))}
        </div>

        <div className="flex items-center gap-1.5">
          <a
            href={secondaryCta.href}
            className={cn(
              buttonVariants({ variant: "ghost" }),
              "hidden text-muted-foreground sm:inline-flex"
            )}
          >
            {secondaryCta.label}
          </a>
          <a href={primaryCta.href} className={buttonVariants()}>
            {primaryCta.label}
          </a>
          <button
            type="button"
            aria-expanded={open}
            aria-controls={panelId}
            onClick={() => setOpen((v) => !v)}
            className={cn(
              buttonVariants({ variant: "ghost", size: "icon-sm" }),
              "md:hidden"
            )}
          >
            {open ? <X /> : <Menu />}
            <span className="sr-only">{open ? "Close menu" : "Open menu"}</span>
          </button>
        </div>
      </nav>

      {open && (
        <motion.div
          id={panelId}
          initial="hidden"
          animate="visible"
          variants={fadeUp}
          className="border-t bg-background/95 backdrop-blur-md md:hidden"
        >
          <div className="mx-auto flex max-w-6xl flex-col gap-1 px-6 py-4">
            {links.map((link) => (
              <a
                key={link.label}
                href={link.href}
                onClick={() => setOpen(false)}
                className="rounded-lg px-3 py-2.5 text-sm font-medium text-muted-foreground transition-colors hover:bg-muted hover:text-foreground"
              >
                {link.label}
              </a>
            ))}
            <a
              href={secondaryCta.href}
              onClick={() => setOpen(false)}
              className="rounded-lg px-3 py-2.5 text-sm font-medium text-muted-foreground transition-colors hover:bg-muted hover:text-foreground sm:hidden"
            >
              {secondaryCta.label}
            </a>
          </div>
        </motion.div>
      )}
    </header>
  )
}