Hulya Karakaya A frontend developer interested in open source and building amazing websites. I believe in building through collaboration and contribution.

Building a responsive navbar in Tailwind CSS

7 min read 2201

Editor’s note: This article was updated on 28 January 2021 to include information on Tailwind CSS v3, which was released in December 2021.

Tailwind CSS, a utility-based CSS framework, makes it possible to create web pages without writing a single line of CSS. It’s packed with utility classes that allow you to build any design directly from your markup.

Current internet consumers who are visiting your webpage will have diverse screen and window sizes, from large desktops to small mobile phones or tablets. As a developer, we need to make the site look good on each of these.

Historically, this has been a challenge with CSS. Creating responsive components involves adding media queries and layout methods (like Flexbox and Grid), checking every part to make sure it looks good, then tweaking the code accordingly.

The good news is that Tailwind can ease your struggle with CSS and even help you build user interfaces faster than ever, just by adding class names inside your HTML code. In this article, I will explain how to build a responsive menu with Tailwind to show you how easy it is to create functional, responsive components without touching a line of CSS.

Tailwind CSS released version 3 in December 2021, and in this article, we’ll use v3 via a CDN link.

Breakpoints in Tailwind CSS

We can create responsive designs fairly quickly with Tailwind, but to target a specific breakpoint, we need to take an existing Tailwind utility class and prefix it with the name of the breakpoint, followed by a column. Yes, that’s it!

For example:

<h1 class="text-black md:text-gray-500">Medium breakpoint</h1>

Here, h1 will be the color black for the smallest sizes and up, but when we hit the medium breakpoint (640px and up), its color will change to grey.

You can see the breakpoints and their corresponding screen sizes below. These sizes are based on a mobile-first approach because they are using min-width in CSS:

Breakpoint prefix Minimum width CSS
sm 640px @media (min-width: 640px) { ... }
md 768px @media (min-width: 768px) { ... }
lg 1024px @media (min-width: 1024px) { ... }
xl 1280px @media (min-width: 1280px) { ... }
2xl 1536px @media (min-width: 1536px) { ... }

Creating responsive navbars in Tailwind CSS

In this tutorial, we will create a responsive navbar. You can follow along with a CodePen.

To work with Tailwind 3, go to SettingsHTMLA Stuff for <head>, and add <script src="https://cdn.tailwindcss.com"></script> CDN link, then save and close. We’ll only be working with HTML, and we will use JavaScript to toggle the button.

You can fork the demo on my CodePen here.

codepen-demo-dynamic-menu-tailwind-css

Let’s get started. Go to the HTML tab, then add a body, header and nav tag like so:

<body>
  <header>
    <nav>
      <!--  Code goes here      -->
    </nav>
  </header>
</body>

We will create the navbar inside our nav tag. I added some starter code to make it look better:

<body
    class="
      antialiased
      bg-gradient-to-r
      from-pink-300
      via-purple-300
      to-indigo-400
    "
  >
  <header>
     <nav
        class="
          flex flex-wrap
          items-center
          justify-between
          w-full
          py-4
          md:py-0
          px-4
          text-lg text-gray-700
          bg-white
        "
      >
      <!--  Code goes here      -->
    </nav>
  </header>
</body>

For the body element, we have a gradient background via bg-gradient-to-r from-pink-300 via-purple-300 to-indigo-400 and a font smoothing effect via antialiased.

The nav element has its display property set via flex. This places flex items along the nav’s x-axis and gives them an equal amount of space between each item via justify-between. Then, to wrap the child elements if necessary, we have a flex-wrap utility class.

We are giving a 100 percent width via w-full with 1rem of top and bottom padding (vertically) via py-4. 1rem top and bottom padding will only work from the smallest screen size up to a certain point. We need to make adjustments to the padding on the top and bottom after a medium breakpoint: 768px and up. We remove the padding with the md:py-0 class.

For the right and left padding, we have 1rem horizontal padding with px-4.

For the text size, we added text-lg, which will make the font size 1.125rem and line height 1.75rem.



Last, we added a dark gray text color with text-gray-700.

Placing the logo

Inside the nav tag, we will nest a div with a link element, and a svg tag for our logo. You can put whatever logo you want here:

<div>
          <a href="#">
            <svg
              xmlns="<http://www.w3.org/2000/svg>"
              width="150"
              height="32.125"
              viewBox="0 0 150 32.125"
            >
              <g
                id="Group_330"
                data-name="Group 330"
                transform="translate(-251.1 457.654)"
              >
                <g
                  id="Group_329"
                  data-name="Group 329"
                  transform="translate(251.1 -457.654)"
                >
                  <path
                    id="Path_121"
                    data-name="Path 121"
                    d="M257.887-454.034a12.084,12.084,0,0,1,3.505-3.62,11.811,11.811,0,0,1,3.46,3.549,17.887,17.887,0,0,1,3.362,11.216c.73.589,1.482,1.154,2.2,1.754a3.969,3.969,0,0,1,1.266,3.659c-.347,1.672-.679,3.347-1.045,5.015a1.393,1.393,0,0,1-2.12.7c-1.178-.946-2.326-1.925-3.5-2.872a5.373,5.373,0,0,1-3.316,1.44,5.365,5.365,0,0,1-3.882-1.4c-.844.621-1.628,1.367-2.453,2.033a6.315,6.315,0,0,1-1.2.924,1.393,1.393,0,0,1-1.839-.9c-.377-1.631-.771-3.257-1.136-4.89a3.96,3.96,0,0,1,1.335-3.81c.641-.517,1.29-1.025,1.943-1.527.182-.092.091-.3.1-.46a17.915,17.915,0,0,1,3.326-10.806m1.156,5.049a2.748,2.748,0,0,0,.24,3.641,3.024,3.024,0,0,0,4.134.085,2.75,2.75,0,0,0,.729-3.021,2.924,2.924,0,0,0-2.454-1.825,2.984,2.984,0,0,0-2.65,1.119"
                    transform="translate(-251.1 457.654)"
                    fill="#764abc"
                  />
                  <path
                    id="Path_122"
                    data-name="Path 122"
                    d="M260.3-419.746a.693.693,0,0,1,1.027-.557,6.628,6.628,0,0,0,5.77,0,.7.7,0,0,1,1.029.516q.008,1.532,0,3.064a.691.691,0,0,1-1.079.5c-.306-.26-.582-.552-.876-.825-.467.874-.905,1.76-1.375,2.631a.7.7,0,0,1-1.161.007c-.472-.873-.908-1.764-1.384-2.637-.29.275-.566.566-.873.825a.692.692,0,0,1-1.078-.506c-.008-1.007,0-2.015,0-3.022"
                    transform="translate(-253.92 446.225)"
                    fill="#764abc"
                  />
                  <path
                    id="Path_123"
                    data-name="Path 123"
                    d="M265.28-441.9a1.4,1.4,0,0,0,1.432-1.376,1.4,1.4,0,0,0-1.432-1.377,1.4,1.4,0,0,0-1.431,1.377,1.4,1.4,0,0,0,1.431,1.376"
                    transform="translate(-255.01 453.668)"
                    fill="#764abc"
                  />
                  <path
                    id="Path_124"
                    data-name="Path 124"
                    d="M288.561-448.233H290.8v15.127h9.357v2.036h-11.6Zm13.563,11.211a5.99,5.99,0,0,1,.546-2.557,6.4,6.4,0,0,1,1.479-2.037,6.769,6.769,0,0,1,4.751-1.818,6.592,6.592,0,0,1,4.666,1.733,5.891,5.891,0,0,1,1.891,4.521,5.9,5.9,0,0,1-2.024,4.544,6.767,6.767,0,0,1-4.751,1.807A6.582,6.582,0,0,1,304-432.549a5.832,5.832,0,0,1-1.879-4.472m2.3-.133a4.517,4.517,0,0,0,.339,1.757A4.36,4.36,0,0,0,305.7-434a4.381,4.381,0,0,0,3.2,1.235,4.1,4.1,0,0,0,3.03-1.235,4.107,4.107,0,0,0,1.224-3.043,4.325,4.325,0,0,0-1.273-3.188,4.335,4.335,0,0,0-3.2-1.26,4.074,4.074,0,0,0-3.03,1.249,4.213,4.213,0,0,0-1.224,3.091m16.677,1.078a2.077,2.077,0,0,0-.582,1.3.918.918,0,0,0,.413.849,3.845,3.845,0,0,0,1.1.413q.692.157,1.564.266t1.794.218q.909.121,1.782.315a6.957,6.957,0,0,1,1.575.509,2.345,2.345,0,0,1,1.516,2.158,4.306,4.306,0,0,1-1.9,3.563,6.821,6.821,0,0,1-4.157,1.321,7.745,7.745,0,0,1-3.806-.873,3.147,3.147,0,0,1-1.831-2.861,3.762,3.762,0,0,1,.9-2.315,5.143,5.143,0,0,1,.558-.606,2.3,2.3,0,0,1-1.758-2.17,4.315,4.315,0,0,1,1.6-3.321,3.385,3.385,0,0,1-.557-1.878,3.7,3.7,0,0,1,.424-1.806,4.118,4.118,0,0,1,1.152-1.321,5.62,5.62,0,0,1,3.5-1.115,5.436,5.436,0,0,1,3.466,1.115,4.661,4.661,0,0,1,2.5-1.043,6.619,6.619,0,0,1,.945-.072l-.1,1.879a6.307,6.307,0,0,0-2.218.569,3.709,3.709,0,0,1,.412,1.721,3.4,3.4,0,0,1-.436,1.7,4.025,4.025,0,0,1-1.14,1.31,5.554,5.554,0,0,1-3.405,1.091,5.887,5.887,0,0,1-3.309-.91m.582-4.253a2.143,2.143,0,0,0-.231,1.017,2.221,2.221,0,0,0,.231,1.031,2.275,2.275,0,0,0,.654.739,3.493,3.493,0,0,0,2.085.582,2.688,2.688,0,0,0,2.594-1.285,2.074,2.074,0,0,0,.231-1.006,2.135,2.135,0,0,0-.243-1.03,2.124,2.124,0,0,0-.642-.751,3.446,3.446,0,0,0-2.085-.594,2.682,2.682,0,0,0-2.594,1.3m.024,8.944a3.151,3.151,0,0,0-.837,2.194,1.783,1.783,0,0,0,1.2,1.611,4.619,4.619,0,0,0,1.975.473,7.943,7.943,0,0,0,1.6-.134,3.885,3.885,0,0,0,1.139-.4,1.942,1.942,0,0,0,1.176-1.769q0-1.079-2.085-1.443-.9-.157-2.194-.279t-1.975-.254m27.052-11.563a5.27,5.27,0,0,1-3.515,5.273l3.261,6.606H345.9l-2.945-5.976a16.725,16.725,0,0,1-2.509.182h-4.461v5.793h-2.241v-17.163h7.042a12.082,12.082,0,0,1,5.684,1.042,4.451,4.451,0,0,1,2.291,4.242m-8.012,4.048a8.338,8.338,0,0,0,4.024-.752,3.344,3.344,0,0,0,1.612-3.151q0-2.885-3.733-3.273a19.936,19.936,0,0,0-2.218-.121h-4.449v7.3Zm10.7,1.879a5.99,5.99,0,0,1,.546-2.557,6.4,6.4,0,0,1,1.479-2.037,6.77,6.77,0,0,1,4.751-1.818A6.591,6.591,0,0,1,362.9-441.7a5.894,5.894,0,0,1,1.891,4.521,5.9,5.9,0,0,1-2.024,4.544,6.767,6.767,0,0,1-4.751,1.807,6.582,6.582,0,0,1-4.678-1.721,5.831,5.831,0,0,1-1.879-4.472m2.3-.133a4.517,4.517,0,0,0,.34,1.757,4.37,4.37,0,0,0,.933,1.394,4.383,4.383,0,0,0,3.2,1.235,4.1,4.1,0,0,0,3.03-1.235,4.107,4.107,0,0,0,1.224-3.043,4.325,4.325,0,0,0-1.273-3.188,4.336,4.336,0,0,0-3.2-1.26,4.073,4.073,0,0,0-3.03,1.249,4.214,4.214,0,0,0-1.224,3.091m23.344,3.491.424,1.709a7.408,7.408,0,0,1-4.46,1.127,5.729,5.729,0,0,1-4.412-1.721,6.409,6.409,0,0,1-1.563-4.557,6.234,6.234,0,0,1,1.757-4.509,5.974,5.974,0,0,1,4.448-1.818,6.431,6.431,0,0,1,3.9,1.1l-.8,1.805a5.411,5.411,0,0,0-3.321-1.017,3.3,3.3,0,0,0-2.7,1.284,4.622,4.622,0,0,0-.982,3.006,4.82,4.82,0,0,0,1.03,3.175,3.638,3.638,0,0,0,2.969,1.309,8.3,8.3,0,0,0,3.708-.9m3.066-16.326h2.3v12.133l5.442-5.333h2.69l-5.7,5.575,3.394,3.66a3.824,3.824,0,0,0,2.569,1.249l-.352,1.636a3.724,3.724,0,0,1-2.981-.678,6.8,6.8,0,0,1-.691-.667l-4.375-4.728v6.073h-2.3Zm22.108,7.866a4.441,4.441,0,0,1,1.006,1.624,5.626,5.626,0,0,1,.376,2.049,15.688,15.688,0,0,1-.243,2.533h-8.436a4.022,4.022,0,0,0,1.188,2.315,3.741,3.741,0,0,0,2.606.836,10.169,10.169,0,0,0,4.133-.824l.388,1.733a8.96,8.96,0,0,1-3.564.958,15.618,15.618,0,0,1-1.672.073,6.288,6.288,0,0,1-2.158-.412,4.692,4.692,0,0,1-1.866-1.212,6.631,6.631,0,0,1-1.466-4.654,6.234,6.234,0,0,1,1.757-4.509,5.974,5.974,0,0,1,4.448-1.818,4.733,4.733,0,0,1,3.5,1.309m-.812,4.425.049-.655a2.885,2.885,0,0,0-1.66-2.945,3.332,3.332,0,0,0-1.334-.242,3.368,3.368,0,0,0-1.43.3,3.514,3.514,0,0,0-1.114.825,4.376,4.376,0,0,0-1.091,2.715Zm5.358-3.624h-1.3v-1.5l2.982-2.242h.618v1.879h3.466v1.866h-3.466v4.9a5.311,5.311,0,0,0,.521,2.812,2.747,2.747,0,0,0,2.036.91l-.351,1.636q-3.636.46-4.3-2.873a10.568,10.568,0,0,1-.206-2.144Z"
                    transform="translate(-262.589 455.303)"
                    fill="#764abc"
                  />
                </g>
              </g>
            </svg>
          </a>
        </div>

Adding a hamburger icon for mobile with Tailwind CSS

After the logo, let’s add another SVG for a hamburger icon; You can get the SVG from HeroIcons. This will toggle the menu on mobile screens.

Adding hamburger icon with Tailwind CSS

Let’s analyze its classes:

<svg class="h-6 w-6 cursor-pointer md:hidden block"> </svg>

This icon will appear by default, so even the smallest screen size will see it. But when we hit the medium breakpoint of 768px, the icon will disappear and show the desktop version of the navigation. This happens because we added the md:hidden block classes.

We’re also increasing the height and width of the icon to 1.5rem with h-6 and w-6.

Finally, we have cursor-pointer. When we hover over it, we see that the mouse cursor changes to a pointing hand.

We have also an id of menu-button, which we will use for the JavaScript toggle:

<!-- Hamburger Icon -->
          <svg
            xmlns="<http://www.w3.org/2000/svg>"
            id="menu-button"
            class="h-6 w-6 cursor-pointer md:hidden block"
            fill="none"
            viewBox="0 0 24 24"
            stroke="currentColor"
          >
            <path
              stroke-linecap="round"
              stroke-linejoin="round"
              stroke-width="2"
              d="M4 6h16M4 12h16M4 18h16"
            />
          </svg>

Creating the navigation items with Tailwind CSS

Now we will add our navigation items inside the nav element:

<div class="hidden w-full md:flex md:items-center md:w-auto " id="menu">
          <ul
            class="
              text-base text-gray-700
              pt-4
              md:flex
              md:justify-between
              md:pt-0"
          >
            <li>
              <a class="md:p-4 py-2 block hover:text-purple-400" href="#"
                >Features</a
              >
            </li>
            <li>
              <a class="md:p-4 py-2 block hover:text-purple-400" href="#"
                >Pricing</a
              >
            </li>
            <li>
              <a class="md:p-4 py-2 block hover:text-purple-400" href="#"
                >Customers</a
              >
            </li>
            <li>
              <a class="md:p-4 py-2 block hover:text-purple-400" href="#"
                >Blog</a
              >
            </li>
            <li>
              <a
                class="md:p-4 py-2 block hover:text-purple-400 text-purple-500"
                href="#"
                >Sign Up</a
              >
            </li>
          </ul>
        </div>

For the parent div, we have an id property of menu. Again, we will use this ID to toggle the hamburger menu items with JavaScript.

Let’s analyze its Tailwind utility classes:

<div class="hidden w-full md:flex md:items-center md:justify-between md:w-auto " id="menu"></div>

By default, our menu items will be hidden via the hidden class and have a full width of the w-full class. We will reveal the menu items only after the user toggles the hamburger icon.

However, after the medium breakpoint of 648px, we will show the menu items as flex items with the md:flex, then align the children along the center of div‘s y-axis with md:items-center. It also sets the width as auto with md:w-auto. This will unset the full width and the browser will calculate the size of the element.

Let’s move on to ul:

<ul class="text-base text-gray-700 pt-4 md:flex md:justify-between md:pt-0"></ul>

Text-base will set the font size to 1rem and line height to 1.5rem. We’re giving the ul‘s child elements a text color of dark gray with text-gray-700, and adding 1rem for top padding with pt-4 class. Don’t forget that these are for small screens; Tailwind uses a mobile-first approach.

For the medium breakpoint and onwards, we will have  flex to display the flex items next to each other. Give an equal amount of space to child elements along the container’s x-axis with md:justify-between, and remove the top padding with pt-0.

Let’s move on to the list items now. Li‘s are nested with link tags; let’s examine their classes:

 <li>
    <a class="py-2 block md:p-4 hover:text-purple-400" href="#" >Features</a>
  </li>

Here we have top and bottom padding set to 0.5rem via py-2 and displayed as a block in mobile screens. After the medium breakpoint, we are setting padding to 1rem via md:p-4. There is also a hover effect via hover:text-purple-400, which will turn the list items’ color to light purple.

Toggling the menu with JavaScript

Now that we’re done with the navigation, let’s add the menu toggle implementation with JavaScript.


More great articles from LogRocket:


Go to the JS tab on CodePen, where we will get our menu (or hamburger) icon and the menu that is holding our list items.

With the click event listener, we are toggling the menu’s hidden class when the user clicks on it:

const button = document.querySelector('#menu-button'); // Hamburger Icon
const menu = document.querySelector('#menu'); // Menu

button.addEventListener('click', () => {
  menu.classList.toggle('hidden');
});

Adding text to the page

After the navbar, we can display some text. We have two nested divs with a h1 tag:

<div class="px-4">
      <div
        class="
          flex
          justify-center
          items-center
          bg-white
          mx-auto
          max-w-2xl
          rounded-lg
          my-16
          p-16
        "
      >
        <h1 class="text-2xl font-medium">Responsive Navbar with TailwindCSS</h1>
      </div>
    </div>

The first div has a 1rem right and left padding. This will give us some space when the screen is small.

The second div has a flex display and centers the h1 both horizontally and vertically. It has a white background, and the left and right margins have an auto margin via mx-auto.

For the maximum width, it can grow up to 42rem via max-width-2xl. We also have a 0.5rem border radius with rounded-lg.

my-16 sets the top and bottom margins to 4rem, and p-16 sets padding on all sides.

Lastly, h1 has 1.5rem font size and line height of 1.75rem, and a font weight of 500 via font-medium.

Keep building!

I hope this tutorial helped you understand the capabilities of Tailwind CSS when creating responsive navbars. If you want to create the project from scratch without using CodePen, you’ll need to follow some installation guides, which you can find on the official Tailwind CSS website. Plus, if you run into a problem, you can easily search their site for solutions.

Is your frontend hogging your users' CPU?

As web frontends get increasingly complex, resource-greedy features demand more and more from the browser. If you’re interested in monitoring and tracking client-side CPU usage, memory usage, and more for all of your users in production, try LogRocket.https://logrocket.com/signup/

LogRocket is like a DVR for web and mobile apps, recording everything that happens in your web app, mobile app, or website. Instead of guessing why problems happen, you can aggregate and report on key frontend performance metrics, replay user sessions along with application state, log network requests, and automatically surface all errors.

Modernize how you debug web and mobile apps — .

Hulya Karakaya A frontend developer interested in open source and building amazing websites. I believe in building through collaboration and contribution.

4 Replies to “Building a responsive navbar in Tailwind CSS”

  1. This is bs. This is not responsive navbar. A responsive navbar would switch the color of the page you are on after you click on it. This is a hovering effect, not responsive. Please tell me what is so responsive about this? Total waste of my time setting this all up. If I wanted a hover effect, I couldve just implemented it. Responsive in my eyes is when you click the button, the button lights up to tell you which page your on.

    1. “Responsive” means the component behaves correctly when the screen size changes. e.g. a navbar turns into a hamburger menu on mobile instead of running miles off the side of the page.

      Responsive has nothing to do with spiffing effects like color changes.

      The only total waste of time around here is the energy you spent spouting off at something because you didn’t have the requisite knowledge to understand what’s going on. Be more polite to those that have provided free information that is actually useful to those who know what’s going on.

  2. Hi,
    I’m refactoring an Aurelia 1x app to htmx and using tailwindcss when I thankfully found this post. My routes are parital re-loads and not full page reloads. When in mobile mode I’d like to toggle menu off after making a menu selection which I know is just missing some extra javascript code. Any assistance appeciated,
    Thanks for this terrific post.
    John


    works


Leave a Reply