Navbar

Navbar 01 — Floating Pill

Sticky floating pill navbar with backdrop blur, centered links, rounded CTA and a useState-powered mobile dropdown.

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

Code

Installed to components/sections/navbar-01.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 Navbar01Props = {
  /** Text logo — pass a string or any node. */
  logo?: React.ReactNode
  logoHref?: string
  links?: NavLink[]
  cta?: Cta
  className?: string
}

export function Navbar01({
  logo = "Lumen",
  logoHref = "#",
  links = [
    { label: "Features", href: "#features" },
    { label: "Pricing", href: "#pricing" },
    { label: "Testimonials", href: "#testimonials" },
    { label: "FAQ", href: "#faq" },
  ],
  cta = { label: "Get started", href: "#" },
  className,
}: Navbar01Props) {
  const [open, setOpen] = React.useState(false)
  const panelId = React.useId()

  return (
    <header className={cn("sticky top-0 z-50 w-full px-4 pt-4", className)}>
      <nav aria-label="Main" className="mx-auto max-w-3xl">
        <div className="flex items-center justify-between gap-4 rounded-full border border-border/70 bg-background/70 py-2 pr-2 pl-5 shadow-lg shadow-primary/5 backdrop-blur-xl">
          <a
            href={logoHref}
            className="flex items-center gap-2.5 font-heading text-base font-semibold tracking-tight"
          >
            <span
              aria-hidden
              className="size-4 rounded-full bg-gradient-to-br from-primary to-primary/40 ring-4 ring-primary/15"
            />
            {logo}
          </a>

          <div className="hidden items-center gap-1 md:flex">
            {links.map((link) => (
              <a
                key={link.label}
                href={link.href}
                className="rounded-full 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={cta.href}
              className={cn(buttonVariants({ size: "sm" }), "rounded-full px-4")}
            >
              {cta.label}
            </a>
            <button
              type="button"
              aria-expanded={open}
              aria-controls={panelId}
              onClick={() => setOpen((v) => !v)}
              className={cn(
                buttonVariants({ variant: "ghost", size: "icon-sm" }),
                "rounded-full md:hidden"
              )}
            >
              {open ? <X /> : <Menu />}
              <span className="sr-only">{open ? "Close menu" : "Open menu"}</span>
            </button>
          </div>
        </div>

        {open && (
          <motion.div
            id={panelId}
            initial="hidden"
            animate="visible"
            variants={fadeUp}
            className="mt-2 flex flex-col gap-1 rounded-2xl border border-border/70 bg-background/95 p-2 shadow-xl shadow-primary/5 backdrop-blur-xl md:hidden"
          >
            {links.map((link) => (
              <a
                key={link.label}
                href={link.href}
                onClick={() => setOpen(false)}
                className="rounded-xl px-3 py-2.5 text-sm font-medium text-muted-foreground transition-colors hover:bg-muted hover:text-foreground"
              >
                {link.label}
              </a>
            ))}
          </motion.div>
        )}
      </nav>
    </header>
  )
}