LearnAI ToolsCareerPractice BuildsPlayContact
Lesson 2318 min read

Building a Navigation Bar

Compose a fully responsive navigation bar with Flexbox utilities, spacing scales, and a mobile menu toggle using only Tailwind classes.

Introduction

A navigation bar is one of the first real components every Tailwind developer builds, because it forces you to combine several utilities you already know — Flexbox, spacing, typography, and responsive prefixes — into a single working piece of UI. There is no navbar component in Tailwind itself; you assemble it from utility classes, which means you have full control over exactly how it looks and behaves at every screen size.

What You Will Build
  • A horizontal navbar with a logo on the left and links on the right.
  • Links that collapse into a hamburger menu on small screens.
  • A mobile dropdown panel toggled with a tiny bit of JavaScript.

Start with the outer shell. A navbar is usually a full-width <nav> with a background color, a bottom border or shadow, and horizontal padding that matches the rest of your page.

<nav class="bg-white border-b border-gray-200 px-4 sm:px-6 lg:px-8">
<div class="mx-auto max-w-6xl flex h-16 items-center justify-between">
<!-- logo + links go here -->
</div>
</nav>

mx-auto with a max-w-* class centers the content and caps its width on large screens, while h-16 fixes a consistent navbar height so the layout does not jump as content changes.

Laying Out with Flexbox

flex on the inner container, combined with items-center and justify-between, is the workhorse pattern for navbars: it vertically centers everything and pushes the logo to one edge and the links to the other.

<div class="mx-auto max-w-6xl flex h-16 items-center justify-between">
<a href="/" class="text-xl font-bold text-gray-900">PrograMinds</a>
<div class="hidden md:flex items-center gap-8">
<a href="/" class="text-sm font-medium text-gray-700 hover:text-blue-600">Home</a>
<a href="/courses" class="text-sm font-medium text-gray-700 hover:text-blue-600">Courses</a>
<a href="/about" class="text-sm font-medium text-gray-700 hover:text-blue-600">About</a>
<a href="/contact" class="rounded-md bg-blue-600 px-4 py-2 text-sm font-semibold text-white hover:bg-blue-700">Contact</a>
</div>
</div>
Rendered Result

Click Run to see what this code prints.

Keep link styling consistent by reusing the same combination of classes on every anchor: a text size, a font weight, a default color, and a hover color. Repeating this by hand is fine for now — later lessons show how to extract it with @apply.

<a href="/courses" class="text-sm font-medium text-gray-700 hover:text-blue-600 transition-colors">
Courses
</a>

transition-colors makes the hover color change smooth instead of instant — a small detail that makes a navbar feel polished.

The pair hidden md:flex is the core responsive trick: hidden removes the element from the layout entirely on all screens, and md:flex overrides that starting at the md breakpoint (768px), turning it back into a flex container. Below md the links do not just look invisible — they are removed from the document flow, which is what lets the hamburger icon take their place.

<!-- Links: visible from md upward -->
<div class="hidden md:flex items-center gap-8">...</div>
<!-- Hamburger button: visible only below md -->
<button class="md:hidden inline-flex items-center justify-center rounded-md p-2 text-gray-700 hover:bg-gray-100">
<svg class="h-6 w-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
</svg>
</button>

The Mobile Menu Toggle

Tailwind styles the markup, but showing and hiding the mobile panel still needs a tiny bit of JavaScript to toggle a class. The pattern below works with plain HTML and a few lines of vanilla JS — in a React or Next.js project you would toggle a piece of state instead, which the "Tailwind with React/Next.js" lesson covers.

<nav class="bg-white border-b border-gray-200 px-4">
<div class="mx-auto max-w-6xl flex h-16 items-center justify-between">
<a href="/" class="text-xl font-bold">PrograMinds</a>
<button id="menu-btn" class="md:hidden p-2 text-gray-700">☰</button>
<div class="hidden md:flex gap-8">
<a href="/courses">Courses</a>
<a href="/about">About</a>
</div>
</div>
<!-- mobile panel, hidden by default -->
<div id="mobile-panel" class="hidden md:hidden flex-col gap-1 px-2 pb-4">
<a href="/courses" class="block rounded-md px-3 py-2 text-gray-700 hover:bg-gray-100">Courses</a>
<a href="/about" class="block rounded-md px-3 py-2 text-gray-700 hover:bg-gray-100">About</a>
</div>
</nav>
<script>
const btn = document.getElementById('menu-btn');
const panel = document.getElementById('mobile-panel');
btn.addEventListener('click', () => {
panel.classList.toggle('hidden');
panel.classList.toggle('flex');
});
</script>
Why toggle two classes?

Tailwind's hidden utility sets display: none. Simply removing hidden is not enough if the panel needs display: flex to lay out its links vertically, so the script toggles both hidden and flex together.

Active Link States

Highlighting the current page makes a navbar feel finished. Since Tailwind classes are just strings, you can conditionally apply an "active" set of classes based on the current route in whatever templating or framework you are using.

<!-- Active link -->
<a href="/courses" class="text-sm font-semibold text-blue-600 border-b-2 border-blue-600">
Courses
</a>
<!-- Inactive link -->
<a href="/about" class="text-sm font-medium text-gray-700 hover:text-blue-600">
About
</a>

Common Mistakes

Avoid These Mistakes
  • Forgetting md:hidden on the hamburger button, so it stays visible on desktop alongside the links.
  • Using hidden without a matching display override (like flex) when re-showing the panel, leaving it collapsed even after removing hidden.
  • Not adding a fixed height like h-16, which lets the navbar height jitter as content changes.
  • Hard-coding pixel widths instead of using max-w-* and mx-auto, breaking the layout on ultra-wide screens.

Best Practices

  • Center navbar content with a max-w-* + mx-auto wrapper so it lines up with the rest of the page.
  • Pick one breakpoint (usually md) as the single point where desktop and mobile navigation swap — do not scatter different breakpoints across related elements.
  • Add transition-colors to interactive links and buttons for smoother hover feedback.
  • Use semantic <nav> and <button> elements so the navbar remains accessible to screen readers and keyboard users.

Frequently Asked Questions

No. Tailwind is utility-first, so a navbar is always assembled from primitives like flex, hidden, and the responsive prefixes shown in this lesson.

md (768px) roughly matches tablet width, which is usually where a horizontal link list starts to feel cramped. You can use any breakpoint that fits your design.

Yes — combine the toggle script with transition, duration-*, and opacity/translate utilities, which the "Animations & Transitions" lesson covers in detail.

Key Takeaways

  • flex, items-center, and justify-between are the core layout trio for navbars.
  • hidden md:flex is the standard pattern for swapping between mobile and desktop navigation.
  • The mobile toggle still needs a small amount of JavaScript or framework state — Tailwind only handles the styling.
  • Consistent link classes and a max-width wrapper keep the navbar visually stable across breakpoints.

Summary

You built a responsive navbar using nothing but Flexbox and responsive utilities, and wired up a working mobile menu toggle. In the next lesson you will learn how to stop repeating long class lists like these by extracting them into a custom class with the @apply directive.

Next Lesson →

Custom Classes with @apply