DEV Community

Dylan Muraco
Dylan Muraco

Posted on

Responsive Global Navbar in Next.js with tailwindcss

A navbar is one of the most important parts of a website. Users don't know where to go without one. Lets dive into how to make a responsive navbar in Next.js with tailwindcss. I'll also show you how to make the navbar appear across all pages.

If you don't want to read the whole thing and just want the code go to https://github.com/dmuraco3/navbar

Setting up our environment

creating our project

npx create-next-app@latest navbar
cd navbar
Enter fullscreen mode Exit fullscreen mode

installing Tailwind CSS

npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
Enter fullscreen mode Exit fullscreen mode

configuring template paths

tailwind.config.js

module.exports = {
  content: [
    "./pages/**/*.{js,ts,jsx,tsx}",
    "./components/**/*.{js,ts,jsx,tsx}",
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}
Enter fullscreen mode Exit fullscreen mode

Add the Tailwind directives to your CSS
globals.css

...
@tailwind base;
@tailwind components;
@tailwind utilities;
...
Enter fullscreen mode Exit fullscreen mode

now our environment is all set up and we're ready to go

Building our navbar

create a components folder in your root directory to keep components in.

in this folder make a new file called navbar.js

We're going to create three functions and import one

navbar.js

import {useState} from 'react'

function NavLink({to, children}) {

}
function MobileNav({open, setOpen}) {

}

export default function Navbar() {

}
Enter fullscreen mode Exit fullscreen mode

Let's build the mobile nav first

navbar.js

...
function MobileNav({open, setOpen}) {
    return (
        <div className={`absolute top-0 left-0 h-screen w-screen bg-white transform ${open ? "-translate-x-0" : "-translate-x-full"} transition-transform duration-300 ease-in-out filter drop-shadow-md `}>
            <div className="flex items-center justify-center filter drop-shadow-md bg-white h-20"> {/*logo container*/}
                <a className="text-xl font-semibold" href="/">LOGO</a>
            </div>
            <div className="flex flex-col ml-4">
                <a className="text-xl font-medium my-4" href="/about" onClick={() => setTimeout(() => {setOpen(!open)}, 100)}>
                    About
                </a>
                <a className="text-xl font-normal my-4" href="/contact" onClick={() => setTimeout(() => {setOpen(!open)}, 100)}>
                    Contact
                </a>
            </div>  
        </div>
    )
}
...
Enter fullscreen mode Exit fullscreen mode

now we can build our navbar

navbar.js

export default function Navbar() {
const [open, setOpen] = useState(false)
    return (
        <nav className="flex filter drop-shadow-md bg-white px-4 py-4 h-20 items-center">
            <MobileNav open={open} setOpen={setOpen}/>
            <div className="w-3/12 flex items-center">
                <a className="text-2xl font-semibold" href="/">LOGO</a>
            </div>
            <div className="w-9/12 flex justify-end items-center">

                <div className="z-50 flex relative w-8 h-8 flex-col justify-between items-center md:hidden" onClick={() => {
                    setOpen(!open)
                }}>
                    {/* hamburger button */}
                    <span className={`h-1 w-full bg-black rounded-lg transform transition duration-300 ease-in-out ${open ? "rotate-45 translate-y-3.5" : ""}`} />
                    <span className={`h-1 w-full bg-black rounded-lg transition-all duration-300 ease-in-out ${open ? "w-0" : "w-full"}`} />
                    <span className={`h-1 w-full bg-black rounded-lg transform transition duration-300 ease-in-out ${open ? "-rotate-45 -translate-y-3.5" : ""}`} />
                </div>

                <div className="hidden md:flex">
                    <NavLink to="/contact">
                        CONTACT
                    </NavLink>
                    <NavLink to="/about">
                        ABOUT
                    </NavLink>
                </div>
            </div>
        </nav>
    )
}
Enter fullscreen mode Exit fullscreen mode

Now our navbar depends on NavLink which is a pretty simple component so lets whip that up real quick

navbar.js

function NavLink({to, children}) {
    return <a href={to} className={`mx-4`}>
        {children}
    </a>
}
Enter fullscreen mode Exit fullscreen mode

Now put that all together and we get

navbar.js

import { useState } from 'react'

function NavLink({to, children}) {
    return <a href={to} className={`mx-4`}>
        {children}
    </a>
}

function MobileNav({open, setOpen}) {
    return (
        <div className={`absolute top-0 left-0 h-screen w-screen bg-white transform ${open ? "-translate-x-0" : "-translate-x-full"} transition-transform duration-300 ease-in-out filter drop-shadow-md `}>
            <div className="flex items-center justify-center filter drop-shadow-md bg-white h-20"> {/*logo container*/}
                <a className="text-xl font-semibold" href="/">LOGO</a>
            </div>
            <div className="flex flex-col ml-4">
                <a className="text-xl font-medium my-4" href="/about" onClick={() => setTimeout(() => {setOpen(!open)}, 100)}>
                    About
                </a>
                <a className="text-xl font-normal my-4" href="/contact" onClick={() => setTimeout(() => {setOpen(!open)}, 100)}>
                    Contact
                </a>
            </div>  
        </div>
    )
}

export default function Navbar() {

    const [open, setOpen] = useState(false)
    return (
        <nav className="flex filter drop-shadow-md bg-white px-4 py-4 h-20 items-center">
            <MobileNav open={open} setOpen={setOpen}/>
            <div className="w-3/12 flex items-center">
                <a className="text-2xl font-semibold" href="/">LOGO</a>
            </div>
            <div className="w-9/12 flex justify-end items-center">

                <div className="z-50 flex relative w-8 h-8 flex-col justify-between items-center md:hidden" onClick={() => {
                    setOpen(!open)
                }}>
                    {/* hamburger button */}
                    <span className={`h-1 w-full bg-black rounded-lg transform transition duration-300 ease-in-out ${open ? "rotate-45 translate-y-3.5" : ""}`} />
                    <span className={`h-1 w-full bg-black rounded-lg transition-all duration-300 ease-in-out ${open ? "w-0" : "w-full"}`} />
                    <span className={`h-1 w-full bg-black rounded-lg transform transition duration-300 ease-in-out ${open ? "-rotate-45 -translate-y-3.5" : ""}`} />
                </div>

                <div className="hidden md:flex">
                    <NavLink to="/contact">
                        CONTACT
                    </NavLink>
                    <NavLink to="/about">
                        ABOUT
                    </NavLink>
                </div>
            </div>
        </nav>
    )
}
Enter fullscreen mode Exit fullscreen mode

Making navbar appear on all pages

Now we have our navbar made but we can't see it. We could go into each page function and add our components but that gets repetitive and there's a better way to do it.

In our root level file _app.js we have to import the Navbar component and render it in the root level component

_app.js

import Navbar from '../components/navbar'
import '../styles/globals.css'

function MyApp({ Component, pageProps }) {
  return <>
    <Navbar/>

    <Component {...pageProps} />
  </>
}

export default MyApp

Enter fullscreen mode Exit fullscreen mode

Now you have a working responsive navbar.

Thanks for reading!

Top comments (4)

Collapse
 
maybenoobish profile image
Matthias Kluth

Thanks for the post. But could you explain, why I should create 2 different navigations, if tailwind (or even vanilla css) could handle it with one nav, too.
I personally think, that more redundance delivers more errors.

Collapse
 
dmuraco3 profile image
Dylan Muraco

Thanks for commenting. I Pulled this out of a recent project I've been working on and I chose to separate the code like this to make it more readable and more easy to maintain.

Collapse
 
lazyademola profile image
Lazyademola

the a tag doesn't work with the '/' route ...can you help?

Collapse
 
shawn2776 profile image
Shawn Harrington • Edited

You have to surround the links with

<Link href="/about"></Link>
Enter fullscreen mode Exit fullscreen mode

and remove the href="/" from the a tag. Also be sure to import Link from "next/link";