57
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
creating our project
npx create-next-app@latest navbar
cd navbar
installing Tailwind CSS
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
configuring template paths
tailwind.config.js
module.exports = {
content: [
"./pages/**/*.{js,ts,jsx,tsx}",
"./components/**/*.{js,ts,jsx,tsx}",
],
theme: {
extend: {},
},
plugins: [],
}
Add the Tailwind directives to your CSS
globals.css
...
@tailwind base;
@tailwind components;
@tailwind utilities;
...
now our environment is all set up and we're ready to go
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
import {useState} from 'react'
function NavLink({to, children}) {
}
function MobileNav({open, setOpen}) {
}
export default function Navbar() {
}
Let's build the mobile nav first
...
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>
)
}
...
now we can build our navbar
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>
)
}
Now our navbar depends on NavLink
which is a pretty simple component so lets whip that up real quick
function NavLink({to, children}) {
return <a href={to} className={`mx-4`}>
{children}
</a>
}
Now put that all together and we get
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>
)
}
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
import Navbar from '../components/navbar'
import '../styles/globals.css'
function MyApp({ Component, pageProps }) {
return <>
<Navbar/>
<Component {...pageProps} />
</>
}
export default MyApp
Now you have a working responsive navbar.
Thanks for reading!
57