Dependencies
tailwindcsslucide-react
shadcn/ui components
npx shadcn@latest add buttonnpx shadcn@latest add dropdown-menunpx shadcn@latest add sheet

A navbar is the first component users interact with. These 5 examples cover the most common patterns — basic, dark, dropdown, mobile drawer and transparent-to-solid scroll effect.

Installation

npx shadcn@latest init
npx shadcn@latest add button dropdown-menu sheet
npm install lucide-react

Props Reference

PropTypeDescription
isOpenbooleanMobile menu open state
setIsOpen(v: boolean) => voidToggle mobile menu
scrolledbooleanWhether page has scrolled (transparent variant)

Key Patterns

PatternWhen to use
Basic navbarMost sites
Dark navbarDark-themed apps, dashboards
DropdownSites with multiple sub-sections
Sheet drawerApps with many nav items on mobile
TransparentLanding pages with hero images

1. Basic React Navbar

Clean responsive navbar with logo, nav links and CTA button using Tailwind CSS.

tsx
import { useState } from "react"
import { Menu, X } from "lucide-react"

export default function BasicNavbar() {
  const [isOpen, setIsOpen] = useState(false)

  const links = [
    { label: "Components", href: "/components" },
    { label: "Tutorials", href: "/tutorials" },
    { label: "Templates", href: "/templates" },
    { label: "Pricing", href: "/pricing" },
  ]

  return (
    <nav className="bg-white border-b border-gray-200 sticky top-0 z-50">
      <div className="max-w-7xl mx-auto px-4">
        <div className="flex items-center justify-between h-16">

          {/* Logo */}
          <a href="/" className="font-bold text-xl" style={{ color: "#fd4766" }}>
            BootstrapPlanet
          </a>

          {/* Desktop nav */}
          <div className="hidden md:flex items-center gap-1">
            {links.map((link) => (
              <a
                key={link.href}
                href={link.href}
                className="px-3 py-2 text-sm text-gray-600 hover:text-gray-900 hover:bg-gray-50 rounded-md transition-colors"
              >
                {link.label}
              </a>
            ))}
          </div>

          {/* CTA + mobile toggle */}
          <div className="flex items-center gap-3">
            <a
              href="https://lettstartdesign.com"
              className="hidden md:inline-flex items-center px-4 py-2 text-sm font-semibold text-white rounded-md"
              style={{ background: "#fd4766" }}
              target="_blank"
              rel="noopener"
            >
              Templates →
            </a>
            <button
              className="md:hidden p-2 rounded-md text-gray-500 hover:bg-gray-100"
              onClick={() => setIsOpen(!isOpen)}
            >
              {isOpen ? <X size={20} /> : <Menu size={20} />}
            </button>
          </div>
        </div>

        {/* Mobile menu */}
        {isOpen && (
          <div className="md:hidden border-t border-gray-100 py-2">
            {links.map((link) => (
              <a
                key={link.href}
                href={link.href}
                className="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-50"
                onClick={() => setIsOpen(false)}
              >
                {link.label}
              </a>
            ))}
            <div className="px-4 pt-2 pb-1">
              <a
                href="https://lettstartdesign.com"
                className="block text-center py-2 text-sm font-semibold text-white rounded-md"
                style={{ background: "#fd4766" }}
              >
                Get Templates →
              </a>
            </div>
          </div>
        )}
      </div>
    </nav>
  )
}

2. Dark React Navbar

Dark themed navbar with brand color accent and ghost button style links.

tsx
import { useState } from "react"
import { Menu, X, Code2 } from "lucide-react"

export default function DarkNavbar() {
  const [isOpen, setIsOpen] = useState(false)

  const links = [
    { label: "Components", href: "/components" },
    { label: "React", href: "/react" },
    { label: "Angular", href: "/angular" },
    { label: "Tutorials", href: "/tutorials" },
  ]

  return (
    <nav style={{ background: "#0d0d0d" }} className="border-b border-gray-800 sticky top-0 z-50">
      <div className="max-w-7xl mx-auto px-4">
        <div className="flex items-center justify-between h-16">

          {/* Logo */}
          <div className="flex items-center gap-2">
            <div
              className="w-7 h-7 rounded flex items-center justify-content-center text-white text-xs font-bold"
              style={{ background: "#fd4766" }}
            >
              BP
            </div>
            <span className="font-bold text-white">BootstrapPlanet</span>
          </div>

          {/* Desktop nav */}
          <div className="hidden md:flex items-center gap-1">
            {links.map((link) => (
              <a
                key={link.href}
                href={link.href}
                className="px-3 py-2 text-sm text-gray-400 hover:text-white rounded-md transition-colors"
              >
                {link.label}
              </a>
            ))}
          </div>

          {/* Actions */}
          <div className="flex items-center gap-3">
            <a
              href="/search"
              className="hidden md:flex p-2 text-gray-400 hover:text-white rounded-md transition-colors"
            >
              <Code2 size={18} />
            </a>
            <a
              href="https://lettstartdesign.com"
              className="hidden md:inline-flex items-center px-4 py-2 text-sm font-semibold text-white rounded-md transition-opacity hover:opacity-90"
              style={{ background: "#fd4766" }}
              target="_blank"
              rel="noopener"
            >
              Templates
            </a>
            <button
              className="md:hidden p-2 text-gray-400 hover:text-white"
              onClick={() => setIsOpen(!isOpen)}
            >
              {isOpen ? <X size={20} /> : <Menu size={20} />}
            </button>
          </div>
        </div>

        {/* Mobile */}
        {isOpen && (
          <div className="md:hidden border-t border-gray-800 py-2">
            {links.map((link) => (
              <a
                key={link.href}
                href={link.href}
                className="block px-4 py-2 text-sm text-gray-400 hover:text-white hover:bg-gray-900"
                onClick={() => setIsOpen(false)}
              >
                {link.label}
              </a>
            ))}
          </div>
        )}
      </div>
    </nav>
  )
}

4. React Navbar with shadcn/ui Sheet (Mobile Drawer)

Navbar that opens a full mobile drawer using shadcn/ui Sheet component.

tsx
import { Button } from "@/components/ui/button"
import {
  Sheet,
  SheetContent,
  SheetHeader,
  SheetTitle,
  SheetTrigger,
} from "@/components/ui/sheet"
import { Menu, Home, Package, BookOpen, GitCompare } from "lucide-react"

const links = [
  { label: "Home", href: "/", icon: Home },
  { label: "Components", href: "/components", icon: Package },
  { label: "Tutorials", href: "/tutorials", icon: BookOpen },
  { label: "Comparisons", href: "/vs", icon: GitCompare },
]

export default function SheetNavbar() {
  return (
    <nav className="bg-white border-b sticky top-0 z-50">
      <div className="max-w-7xl mx-auto px-4">
        <div className="flex items-center justify-between h-16">

          <a href="/" className="font-bold text-lg" style={{ color: "#fd4766" }}>
            BootstrapPlanet
          </a>

          {/* Desktop links */}
          <div className="hidden md:flex items-center gap-1">
            {links.map((link) => (
              <a key={link.href} href={link.href}
                className="px-3 py-2 text-sm text-gray-600 hover:text-gray-900 rounded-md">
                {link.label}
              </a>
            ))}
          </div>

          <div className="flex items-center gap-2">
            <Button size="sm" className="hidden md:flex" style={{ background: "#fd4766" }} asChild>
              <a href="https://lettstartdesign.com" target="_blank" rel="noopener">
                Get Templates
              </a>
            </Button>

            {/* Mobile sheet trigger */}
            <Sheet>
              <SheetTrigger asChild>
                <button className="md:hidden p-2 text-gray-500 hover:bg-gray-100 rounded-md">
                  <Menu size={20} />
                </button>
              </SheetTrigger>
              <SheetContent side="left" className="w-72">
                <SheetHeader>
                  <SheetTitle style={{ color: "#fd4766" }}>BootstrapPlanet</SheetTitle>
                </SheetHeader>
                <nav className="mt-6 flex flex-col gap-1">
                  {links.map((link) => {
                    const Icon = link.icon
                    return (
                      <a key={link.href} href={link.href}
                        className="flex items-center gap-3 px-3 py-2.5 text-sm text-gray-700 hover:bg-gray-100 rounded-md">
                        <Icon size={16} className="text-gray-400" />
                        {link.label}
                      </a>
                    )
                  })}
                </nav>
                <div className="mt-6 pt-6 border-t">
                  <Button className="w-full" style={{ background: "#fd4766" }} asChild>
                    <a href="https://lettstartdesign.com" target="_blank" rel="noopener">
                      Browse Templates →
                    </a>
                  </Button>
                  <p className="text-xs text-center text-gray-500 mt-2">
                    Use code FIRST30 for 30% off
                  </p>
                </div>
              </SheetContent>
            </Sheet>
          </div>

        </div>
      </div>
    </nav>
  )
}

5. React Sticky Transparent-to-Solid Navbar

Navbar that starts transparent over a hero and becomes solid white on scroll.

tsx
import { useState, useEffect } from "react"
import { Menu, X } from "lucide-react"

export default function TransparentNavbar() {
  const [scrolled, setScrolled] = useState(false)
  const [isOpen, setIsOpen] = useState(false)

  useEffect(() => {
    const handler = () => setScrolled(window.scrollY > 60)
    window.addEventListener("scroll", handler)
    return () => window.removeEventListener("scroll", handler)
  }, [])

  return (
    <>
      {/* Demo hero to show effect */}
      <div
        className="h-48 flex items-center justify-center text-white text-center"
        style={{ background: "linear-gradient(135deg, #0d0d0d, #1a1a2e)", marginTop: "-64px", paddingTop: "64px" }}
      >
        <p className="text-sm opacity-60">Scroll down to see navbar change</p>
      </div>

      <nav
        className="fixed top-0 left-0 right-0 z-50 transition-all duration-300"
        style={{
          background: scrolled ? "#fff" : "transparent",
          borderBottom: scrolled ? "1px solid #e5e7eb" : "none",
          boxShadow: scrolled ? "0 1px 12px rgba(0,0,0,0.08)" : "none",
        }}
      >
        <div className="max-w-7xl mx-auto px-4">
          <div className="flex items-center justify-between h-16">
            <a
              href="/"
              className="font-bold text-lg transition-colors"
              style={{ color: scrolled ? "#fd4766" : "#fff" }}
            >
              BootstrapPlanet
            </a>

            <div className="hidden md:flex items-center gap-1">
              {["Components", "React", "Angular", "Tutorials"].map((label) => (
                <a
                  key={label}
                  href={`/${label.toLowerCase()}`}
                  className="px-3 py-2 text-sm rounded-md transition-colors"
                  style={{ color: scrolled ? "#4b5563" : "rgba(255,255,255,0.8)" }}
                >
                  {label}
                </a>
              ))}
            </div>

            <div className="flex items-center gap-2">
              <a
                href="https://lettstartdesign.com"
                className="hidden md:inline-flex px-4 py-2 text-sm font-semibold text-white rounded-md"
                style={{ background: "#fd4766" }}
                target="_blank"
                rel="noopener"
              >
                Templates
              </a>
              <button
                className="md:hidden p-2 rounded-md"
                style={{ color: scrolled ? "#6b7280" : "#fff" }}
                onClick={() => setIsOpen(!isOpen)}
              >
                {isOpen ? <X size={20} /> : <Menu size={20} />}
              </button>
            </div>
          </div>

          {isOpen && scrolled && (
            <div className="md:hidden border-t border-gray-100 py-2 bg-white">
              {["Components", "React", "Angular", "Tutorials"].map((label) => (
                <a key={label} href={`/${label.toLowerCase()}`}
                  className="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-50"
                  onClick={() => setIsOpen(false)}>
                  {label}
                </a>
              ))}
            </div>
          )}
        </div>
      </nav>
    </>
  )
}

Frequently Asked Questions

Add position: sticky; top: 0; z-index: 50 via Tailwind: className='sticky top-0 z-50'. Make sure the parent doesn't have overflow: hidden which breaks sticky positioning. For a fixed navbar that's always visible use position: fixed and add padding-top to the body equal to navbar height.
Pass a click handler to each mobile link that calls setIsOpen(false): <a onClick={() => setIsOpen(false)}>. Or use React Router's useNavigate and close on route change with useEffect watching location.pathname.
Use React Router's useLocation hook: const { pathname } = useLocation(). Then compare: className={pathname === link.href ? 'text-red-500 font-semibold' : 'text-gray-600'}. Or use NavLink component which adds activeClassName automatically.
Add an input inside a form element in the navbar. Use useState for the search query and handle form submit. For a command palette style search use shadcn/ui Command component with a trigger button in the navbar.
For simple isOpen toggle useState is fine. For complex navbar state (multiple dropdowns, search query, user menu) use useReducer or a small Zustand store. Don't put navbar state in global Redux/Context unless it needs to be read by many components outside the navbar.

Need a Full React + Next.js Dashboard Template?

Get a complete React + Next.js dashboard with 50+ components — built by the same team behind BootstrapPlanet.

Browse Templates →

Use code FIRST30 for 30% off.

Related Components