DEV Community

Andrés Espejo
Andrés Espejo

Posted on

How to design a simple and beautiful Navbar using NextJS and TailwindCSS

Alt Text
Definitely NextJS has positioned itself as the best React framework at present, offering all the benefits of the library we love so much, in addition to offering extras such as SSR and configuration for SEO.

So, the purpose of this post is to show how easy and intuitive it can be to make a navbar in NextJS with the help of TailwindCSS. For more complexity, I will make a second post in which we will add a global status for the elements of our Navbar to change.

Setup and configuration

So, the first thing that we need is install NextJS with NextCli, in my case I prefer to use Yarn.

yarn create next-app
Enter fullscreen mode Exit fullscreen mode

After creating our application, we proceed to install tailwind and the dependencies we need:

yarn add tailwindcss@latest postcss@latest autoprefixer@latest postcss-cli
Enter fullscreen mode Exit fullscreen mode

After installing our dependencias, we need to do some modifications in App.js and create new files. Let's start by creating the file postcss.config.js , which will be located in the root of the project:

touch postcss.config.js
Enter fullscreen mode Exit fullscreen mode

Inside the file, we will place the following configuration

// postcss.config.js
module.exports = {
  plugins: {
    tailwindcss: {},
    autoprefixer: {},
  },
}
Enter fullscreen mode Exit fullscreen mode

After this, we will create the file tailwind.config.js with the following command

npx tailwindcss init --full
Enter fullscreen mode Exit fullscreen mode

This generates a tailwind.config.js file that we can modify and custom like we want.

Now, we can delete the default generate style created by Next and we need to create two files in the styles folder: main.css and tailwind.css.

Inside the tailwind.css file we need to add this content

/* ./styles/tailwind.css */
@tailwind base;
@tailwind components;
@tailwind utilities;
Enter fullscreen mode Exit fullscreen mode

After that we must modify the App.js and Index.js pages so that they do not conflict with the deleted files.

/* ./pages/index.js               */
import Head from 'next/head';

export default function Home() {
  return (
    <div>
      <Head>
        <title>Create Next App</title>
        <link rel='icon' href='/favicon.ico' />
      </Head>
      <div>Hello World</div>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode
/*   ./styles/_app.js              */
import '../styles/main.css';

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

export default MyApp;
Enter fullscreen mode Exit fullscreen mode

So, before we can work with Tailwind in our Next App, we need to generate a script that compiles the Tailwind classes in our main.css file. Therefore, in the package.json we need to add some scripts

{
  "name": "ourapp",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "build:css": "postcss styles/tailwind.css -o styles/main.css",
    "build:watch": "postcss styles/tailwind.css -o styles/main.css --watch",
    "prod:build": "NODE_ENV=production yarn run build:css && yarn run build"
  },
  "dependencies": {
    "autoprefixer": "^10.1.0",
    "next": "10.0.4",
    "postcss": "^8.2.1",
    "postcss-cli": "^8.3.1",
    "react": "17.0.1",
    "react-dom": "17.0.1",
    "tailwindcss": "^2.0.2"
  }
}
Enter fullscreen mode Exit fullscreen mode

Finally, we need to execute build:css

yarn build:css
Enter fullscreen mode Exit fullscreen mode

And now we can use Tailwind in all out application :D .

Create the directory

Before we start, I'd like to show you the architecture I prefer to use in this type of application
Alt Text

And now we need to insert our component in the Layout. In this case we don't create a layout container, so we add the component directly in Index.js.

/* ./pages/index.js               */
import Head from 'next/head';
import { Navbar } from '../components/Navbar';

export default function Home() {
  return (
    <div>
      <Head>
        <title>Create Next App</title>
        <link rel='icon' href='/favicon.ico' />
      </Head>
      <Navbar />
      <div>Hello World</div>
    </div>
  );
}

Enter fullscreen mode Exit fullscreen mode

Start our component

/*  ./components/Navbar.jsx     */

export const Navbar = () => {
  return (
    <div>

    </div>
  )
}
Enter fullscreen mode Exit fullscreen mode

From the 17 React version it's no neccesary to import react in our functional components.

We will start by defining the grid which in this case will be flex, the padding and the background color

/*  ./components/Navbar.jsx     */

export const Navbar = () => {
  return (
    <>
      <nav className='flex items-center flex-wrap bg-green-300 p-3 '></nav>
    </>
  );
};

Enter fullscreen mode Exit fullscreen mode

Next offers us its beautiful and useful tool Link for the redirection inside our SPA, so in this case we will use it for the logo and it will redirect us to the "Home" or main view of our application.

/*  ./components/Navbar.jsx     */
import Link from 'next/link';

export const Navbar = () => {
  return (
    <>
      <nav className='flex items-center flex-wrap bg-green-300 p-3 '>
        <Link href='/'>
          <a className='inline-flex items-center p-2 mr-4 '>
            <svg
              viewBox='0 0 24 24'
              xmlns='http://www.w3.org/2000/svg'
              className='fill-current text-white h-8 w-8 mr-2'
            >
              <path d='M12.001 4.8c-3.2 0-5.2 1.6-6 4.8 1.2-1.6 2.6-2.2 4.2-1.8.913.228 1.565.89 2.288 1.624C13.666 10.618 15.027 12 18.001 12c3.2 0 5.2-1.6 6-4.8-1.2 1.6-2.6 2.2-4.2 1.8-.913-.228-1.565-.89-2.288-1.624C16.337 6.182 14.976 4.8 12.001 4.8zm-6 7.2c-3.2 0-5.2 1.6-6 4.8 1.2-1.6 2.6-2.2 4.2-1.8.913.228 1.565.89 2.288 1.624 1.177 1.194 2.538 2.576 5.512 2.576 3.2 0 5.2-1.6 6-4.8-1.2 1.6-2.6 2.2-4.2 1.8-.913-.228-1.565-.89-2.288-1.624C10.337 13.382 8.976 12 6.001 12z' />
            </svg>
            <span className='text-xl text-white font-bold uppercase tracking-wide'>
              TalwindCSS
            </span>
          </a>
        </Link>
      </nav>
    </>
  );
};
Enter fullscreen mode Exit fullscreen mode

Alt Text

For now we have a simple view. Now we will proceed to add the hamburger menu that will be seen in smartphones and tablets:

/*  ./components/Navbar.jsx     */
import Link from 'next/link';

export const Navbar = () => {
  return (
    <>
      <nav className='flex items-center flex-wrap bg-green-300 p-3 '>
        <Link href='/'>
          <a className='inline-flex items-center p-2 mr-4 '>
            <svg
              viewBox='0 0 24 24'
              xmlns='http://www.w3.org/2000/svg'
              className='fill-current text-white h-8 w-8 mr-2'
            >
              <path d='M12.001 4.8c-3.2 0-5.2 1.6-6 4.8 1.2-1.6 2.6-2.2 4.2-1.8.913.228 1.565.89 2.288 1.624C13.666 10.618 15.027 12 18.001 12c3.2 0 5.2-1.6 6-4.8-1.2 1.6-2.6 2.2-4.2 1.8-.913-.228-1.565-.89-2.288-1.624C16.337 6.182 14.976 4.8 12.001 4.8zm-6 7.2c-3.2 0-5.2 1.6-6 4.8 1.2-1.6 2.6-2.2 4.2-1.8.913.228 1.565.89 2.288 1.624 1.177 1.194 2.538 2.576 5.512 2.576 3.2 0 5.2-1.6 6-4.8-1.2 1.6-2.6 2.2-4.2 1.8-.913-.228-1.565-.89-2.288-1.624C10.337 13.382 8.976 12 6.001 12z' />
            </svg>
            <span className='text-xl text-white font-bold uppercase tracking-wide'>
              Talwind CSS
            </span>
          </a>
        </Link>
        <button className=' inline-flex p-3 hover:bg-green-600 rounded lg:hidden text-white ml-auto hover:text-white outline-none'>
          <svg
            className='w-6 h-6'
            fill='none'
            stroke='currentColor'
            viewBox='0 0 24 24'
            xmlns='http://www.w3.org/2000/svg'
          >
            <path
              strokeLinecap='round'
              strokeLinejoin='round'
              strokeWidth={2}
              d='M4 6h16M4 12h16M4 18h16'
            />
          </svg>
        </button>
      </nav>
    </>
  );
};
Enter fullscreen mode Exit fullscreen mode

Alt Text

Excellent, now we will proceed to add the view to be had in computers:

/*  ./components/Navbar.jsx     */
import Link from 'next/link';

export const Navbar = () => {
  return (
    <>
      <nav className='flex items-center flex-wrap bg-green-400 p-3 '>
        <Link href='/'>
          <a className='inline-flex items-center p-2 mr-4 '>
            <svg
              viewBox='0 0 24 24'
              xmlns='http://www.w3.org/2000/svg'
              className='fill-current text-white h-8 w-8 mr-2'
            >
              <path d='M12.001 4.8c-3.2 0-5.2 1.6-6 4.8 1.2-1.6 2.6-2.2 4.2-1.8.913.228 1.565.89 2.288 1.624C13.666 10.618 15.027 12 18.001 12c3.2 0 5.2-1.6 6-4.8-1.2 1.6-2.6 2.2-4.2 1.8-.913-.228-1.565-.89-2.288-1.624C16.337 6.182 14.976 4.8 12.001 4.8zm-6 7.2c-3.2 0-5.2 1.6-6 4.8 1.2-1.6 2.6-2.2 4.2-1.8.913.228 1.565.89 2.288 1.624 1.177 1.194 2.538 2.576 5.512 2.576 3.2 0 5.2-1.6 6-4.8-1.2 1.6-2.6 2.2-4.2 1.8-.913-.228-1.565-.89-2.288-1.624C10.337 13.382 8.976 12 6.001 12z' />
            </svg>
            <span className='text-xl text-white font-bold uppercase tracking-wide'>
              Talwind CSS
            </span>
          </a>
        </Link>
        <button className=' inline-flex p-3 hover:bg-green-600 rounded lg:hidden text-white ml-auto hover:text-white outline-none'>
          <svg
            className='w-6 h-6'
            fill='none'
            stroke='currentColor'
            viewBox='0 0 24 24'
            xmlns='http://www.w3.org/2000/svg'
          >
            <path
              strokeLinecap='round'
              strokeLinejoin='round'
              strokeWidth={2}
              d='M4 6h16M4 12h16M4 18h16'
            />
          </svg>
        </button>
        <div className='hidden w-full lg:inline-flex lg:flex-grow lg:w-auto'>
          <div className='lg:inline-flex lg:flex-row lg:ml-auto lg:w-auto w-full lg:items-center items-start  flex flex-col lg:h-auto'>
            <Link href='/'>
              <a className='lg:inline-flex lg:w-auto w-full px-3 py-2 rounded text-white font-bold items-center justify-center hover:bg-green-600 hover:text-white '>
                Home
              </a>
            </Link>
            <Link href='/'>
              <a className='lg:inline-flex lg:w-auto w-full px-3 py-2 rounded text-white font-bold items-center justify-center hover:bg-green-600 hover:text-white'>
                Services
              </a>
            </Link>
            <Link href='/'>
              <a className='lg:inline-flex lg:w-auto w-full px-3 py-2 rounded text-white font-bold items-center justify-center hover:bg-green-600 hover:text-white'>
                About us
              </a>
            </Link>
            <Link href='/'>
              <a className='lg:inline-flex lg:w-auto w-full px-3 py-2 rounded text-white font-bold items-center justify-center hover:bg-green-600 hover:text-white'>
                Contact us
              </a>
            </Link>
          </div>
        </div>
      </nav>
    </>
  );
};

Enter fullscreen mode Exit fullscreen mode

So, now we hace the deskopt view:
Alt Text

After of this, we need a function that shows or hidden the menu when we click in the hamburger menu. For this we create a state using the useState hook and a function for the button when we click on it:

/*  ./components/Navbar.jsx     */
import Link from 'next/link';
import { useState } from 'react';

export const Navbar = () => {
  const [active, setActive] = useState(false);

  const handleClick = () => {
    setActive(!active);
  };

  return (
    <>
      <nav className='flex items-center flex-wrap bg-green-400 p-3 '>
        <Link href='/'>
          <a className='inline-flex items-center p-2 mr-4 '>
            <svg
              viewBox='0 0 24 24'
              xmlns='http://www.w3.org/2000/svg'
              className='fill-current text-white h-8 w-8 mr-2'
            >
              <path d='M12.001 4.8c-3.2 0-5.2 1.6-6 4.8 1.2-1.6 2.6-2.2 4.2-1.8.913.228 1.565.89 2.288 1.624C13.666 10.618 15.027 12 18.001 12c3.2 0 5.2-1.6 6-4.8-1.2 1.6-2.6 2.2-4.2 1.8-.913-.228-1.565-.89-2.288-1.624C16.337 6.182 14.976 4.8 12.001 4.8zm-6 7.2c-3.2 0-5.2 1.6-6 4.8 1.2-1.6 2.6-2.2 4.2-1.8.913.228 1.565.89 2.288 1.624 1.177 1.194 2.538 2.576 5.512 2.576 3.2 0 5.2-1.6 6-4.8-1.2 1.6-2.6 2.2-4.2 1.8-.913-.228-1.565-.89-2.288-1.624C10.337 13.382 8.976 12 6.001 12z' />
            </svg>
            <span className='text-xl text-white font-bold uppercase tracking-wide'>
              Talwind CSS
            </span>
          </a>
        </Link>
        <button
          className=' inline-flex p-3 hover:bg-green-600 rounded lg:hidden text-white ml-auto hover:text-white outline-none'
          onClick={handleClick}
        >
          <svg
            className='w-6 h-6'
            fill='none'
            stroke='currentColor'
            viewBox='0 0 24 24'
            xmlns='http://www.w3.org/2000/svg'
          >
            <path
              strokeLinecap='round'
              strokeLinejoin='round'
              strokeWidth={2}
              d='M4 6h16M4 12h16M4 18h16'
            />
          </svg>
        </button>
        {/*Note that in this div we will use a ternary operator to decide whether or not to display the content of the div  */}
        <div
          className={`${
            active ? '' : 'hidden'
          }   w-full lg:inline-flex lg:flex-grow lg:w-auto`}
        >
          <div className='lg:inline-flex lg:flex-row lg:ml-auto lg:w-auto w-full lg:items-center items-start  flex flex-col lg:h-auto'>
            <Link href='/'>
              <a className='lg:inline-flex lg:w-auto w-full px-3 py-2 rounded text-white font-bold items-center justify-center hover:bg-green-600 hover:text-white '>
                Home
              </a>
            </Link>
            <Link href='/'>
              <a className='lg:inline-flex lg:w-auto w-full px-3 py-2 rounded text-white font-bold items-center justify-center hover:bg-green-600 hover:text-white'>
                Services
              </a>
            </Link>
            <Link href='/'>
              <a className='lg:inline-flex lg:w-auto w-full px-3 py-2 rounded text-white font-bold items-center justify-center hover:bg-green-600 hover:text-white'>
                About us
              </a>
            </Link>
            <Link href='/'>
              <a className='lg:inline-flex lg:w-auto w-full px-3 py-2 rounded text-white font-bold items-center justify-center hover:bg-green-600 hover:text-white'>
                Contact us
              </a>
            </Link>
          </div>
        </div>
      </nav>
    </>
  );
};

Enter fullscreen mode Exit fullscreen mode

Alt Text

And that it's all. Now we have our beatufil and simple Navbar using NextJS and TailwindCSS.

I recommend a lot that you visit the documentation of Tailwind and Next.

NextJS
TailwindCSS

Both are powerful frameworks with great documentation that will allow us to stand out more and learn every day to improve as developers.
I hope to write the second part of this article soon, where with the help of useContext we will add a user section and change the navbar view depending if the user is logged in or not.

Plus: If you love React and you're looking for a simple and beautiful icons definitively you'll love HeroIcons. Here I let you their official page :D

HeroIcons

Merry Christmas and enjoy with your families.

Top comments (17)

Collapse
 
heymarkkop profile image
Mark Kop

In this example we're using only the Home page. What if I want to use the NavBar for every page?
Should I import it on _app.js or _document.js?

Collapse
 
andrewespejo profile image
Andrés Espejo

In that case is better that you create a Layout in the Pages folder, if you need more help please let me know

Collapse
 
aegirorn profile image
aegirorn

I tried this code which works nicely. Thank you very much.

But I seem to have a problem when it gets down to mobile size. Then the hamburger no longer works - it cannot be clicked. The hamburger works fine in tablet size. Any idea why this is and how to fix it?

Collapse
 
tiaxter profile image
tiaxter • Edited

Hi, I tried this code. And it works nicely. To obtain a menu opening transition I added useRef hook, and so when active set the menu content height equal to refElement.current.scrollHeight + 'px'.

Here my example:
dev-to-uploads.s3.amazonaws.com/up...

Collapse
 
kirtirajsinh profile image
kirtirajsinh

Can you share the useRef function. it'll be helpful

Collapse
 
shadowtime2000 profile image
shadowtime2000

NextJS has built in PostCSS support so why are you running PostCSS from the command line?

Collapse
 
andrewespejo profile image
Andrés Espejo

I prefer using a different file that tailwind.css, but you're right. You can work directly with the tailwind.css file and you don't need to run Postcss from the command line :D

Collapse
 
luisrieke profile image
Luis Rieke

Just wanted to say thank you ❤️ This was perfect!

Collapse
 
josignat profile image
José Ignacio

Hola, yo estoy usando el componente Image para el logo como puedo darle estilos con Taildwind? Probé con className pero no funcionó tampoco con css module

Collapse
 
adedayo888 profile image
dayo adeniji

Very useful resource, Thank You.
Ade

Collapse
 
frankismartinez profile image
frank martinez

Just borrowed your mobile menu approach for a Web3 Dapp... gracias!

Collapse
 
isaactait profile image
Isaac Tait

I implemented this on iloveto.fish Thank you! Great work :D

Collapse
 
xnox profile image
Everton Sales

After testing lots and lots of NavBars, this one is the best. Thank you

Collapse
 
nashthecoder profile image
Nash The Coder

thank you so much for this blog. It has really helped me with a project I am working on.

Collapse
 
akilesh profile image
Akilesh

I have been developing web applications for 2 years now. Tailwind and your blog made my work much easier thanks to that.

Collapse
 
robbyph profile image
Robby • Edited

Any suggestions for animating/transitioning this? I've tried using HeadlessUI and React-Transition-Group and neither have worked with this tutorial.

Collapse
 
r11 profile image
Peter Jaffray

I added an overlay and then
<div
className="fixed inset-0 bg-gray-800 navbar-backdrop opacity-80"
onClick={handleClick}
<
</div>