Skip to content

Tailwind Navbar

A navbar is one of the first components most projects need, and it touches almost everything you've learned so far: flexbox, spacing, position, and responsive design. This lesson builds a complete, responsive navbar.

What Does a Tailwind Navbar Need?

A functional navbar needs a flex container to align a logo and navigation links, responsive utilities to hide the full link list on mobile in favor of a toggleable menu, and often sticky or fixed positioning to stay visible while scrolling.

Structurally, a navbar is simply nav + flex items-center justify-between, everything else builds on that same foundational pattern from the Flexbox and Justify Content lessons.

<nav class="flex items-center justify-between border-b bg-white px-6 py-4">
  <a href="/" class="text-lg font-bold">Brand</a>
  <div class="hidden gap-6 md:flex">
    <a href="/features" class="text-slate-600 hover:text-slate-900">Features</a>
    <a href="/pricing" class="text-slate-600 hover:text-slate-900">Pricing</a>
  </div>
</nav>

The link list is hidden below the md breakpoint, ready to be replaced by a mobile menu toggle.

Navbar Structure Syntax

<nav class="flex items-center justify-between">
  <!-- logo -->
  <div class="hidden md:flex">...</div>  <!-- desktop links -->
  <button class="md:hidden">...</button> <!-- mobile toggle -->
</nav>
  • flex items-center justify-between aligns the logo and links across the row.
  • hidden md:flex shows full navigation only at the md breakpoint and above.
  • md:hidden shows the mobile menu button only below the md breakpoint.
  • sticky top-0 or fixed top-0 keeps the navbar visible while the page scrolls.

Navbar Cheatsheet

Common navbar utility combinations.

Purpose Classes Notes
Navbar container flex items-center justify-between px-6 py-4 Base layout for logo and links
Sticky navbar sticky top-0 z-30 bg-white Stays visible while scrolling
Desktop links hidden gap-6 md:flex Hidden on mobile, visible from md up
Mobile toggle button md:hidden Only visible below md breakpoint
Active link text-blue-600 font-semibold Highlights the current page
Mobile menu panel absolute inset-x-0 top-full Dropdown panel below the navbar
Shadow on scroll shadow-sm (toggled by JS) Adds elevation once page scrolls
CTA button in nav rounded-lg bg-blue-600 px-4 py-2 text-white Prominent call-to-action

Building a Mobile Menu Toggle

On small screens, replace the full link list with a single toggle button that reveals a menu panel, typically absolutely positioned below the navbar, when clicked. This requires a small amount of JavaScript to toggle a hidden class.

<nav class="relative flex items-center justify-between px-6 py-4">
  <a href="/" class="font-bold">Brand</a>
  <button id="menu-toggle" class="md:hidden" aria-expanded="false" aria-controls="mobile-menu">
    <span class="sr-only">Toggle menu</span>
    ☰
  </button>
  <div id="mobile-menu" class="absolute inset-x-0 top-full hidden flex-col gap-4 bg-white p-6 shadow-lg md:static md:flex md:flex-row md:p-0 md:shadow-none">
    <a href="/features">Features</a>
    <a href="/pricing">Pricing</a>
  </div>
</nav>

<script>
  const toggle = document.getElementById("menu-toggle");
  const menu = document.getElementById("mobile-menu");
  toggle.addEventListener("click", () => {
    const isOpen = !menu.classList.contains("hidden");
    menu.classList.toggle("hidden");
    toggle.setAttribute("aria-expanded", String(!isOpen));
  });
</script>

On desktop, md:static md:flex overrides the mobile absolute/hidden positioning so the same markup works at both sizes.

Accessible Navigation

Navigation should always live inside a <nav> element, and mobile menu toggles need proper ARIA attributes so screen reader and keyboard users understand the menu's current open/closed state.

  • Wrap navigation links in a <nav> element with an appropriate aria-label if there are multiple navs on the page.
  • Use aria-expanded and aria-controls on the mobile menu toggle button.
  • Ensure the mobile menu is reachable and closeable using only the keyboard.

Common Mistakes

  • Building the mobile menu toggle without aria-expanded, leaving screen reader users unaware of its open/closed state.
  • Forgetting z-* on a sticky navbar, causing dropdown menus or hero content to render above it unexpectedly.
  • Not testing the mobile menu with keyboard-only navigation (Tab, Enter, Escape).
  • Using fixed instead of sticky without adding matching top padding elsewhere, causing content to hide behind the fixed navbar.
  • Hardcoding the "active" link state instead of deriving it from the current route.

Key Takeaways

  • A navbar is built from the same flexbox and responsive utilities covered earlier in this course.
  • Mobile menus typically toggle a hidden class via a small JavaScript event listener.
  • Sticky navbars need a z-index high enough to stay above other page content.
  • Active link styling should be derived dynamically from the current route, not hardcoded.
  • Accessible navbars require aria-expanded, aria-controls, and full keyboard operability for their mobile toggle.

Pro Tip

Reuse the exact same mobile-menu markup and classes across every page by extracting the navbar into its own component, that way accessibility and responsive fixes only need to happen in one place.