DEV Community

Cover image for How to Create a Side Navigation Bar using React and Tailwind
Francisco Mendes
Francisco Mendes

Posted on

How to Create a Side Navigation Bar using React and Tailwind

Overview

There are several approaches that we can take with implementing a Sidebar on our platform, but the design of each of these approaches depends a lot on our page layout, as well as the purpose that Sidebar will serve.

Obviously Sidebar has only one purpose, which is to provide the user with navigation in our application. But there are some principles that we should take into account, such as:

  • Use a Sidebar for five or more destinations;
  • The elements and their groups must be identifiable;
  • The elements must be properly ordered, the most popular or important routes must be first.

These are some of the factors I take into account, but I recommend reading this Material Design page anyway.

Today's example

Today we are going to create a single component, it will be just the Sidebar, this same component will have a small width so as not to take up so much space on the screen, however it has to be intuitive and very concise.

So that we have an idea of what I'm saying, at the end of this article I hope you get this final result:

final result

Let's code

The framework we are going to use today is Tailwind CSS and along with this framework we are going to use other tools such as classnames and react-icons.

npm install classnames react-icons
Enter fullscreen mode Exit fullscreen mode

After that we will create a file with the name of the navigation elements that we are going to have.

// @src/data/navigation.js
export default ["Home", "Gallery", "Store", "Favorites", "Saved"];
Enter fullscreen mode Exit fullscreen mode

Now we can start working on our Sidebar, more specifically on styling it, the styles that were used were as follows:

/* @src/components/Sidebar.module.css */

.wrapper {
    @apply fixed left-0 top-0 bottom-0 z-50 w-14 bg-white flex flex-col h-screen justify-between items-center py-6 rounded-tr-4xl rounded-br-4xl;
}

.logo {
    @apply text-4xl text-gray-800;
}

.navListItems {
    @apply flex flex-col items-center w-full;
}

.navItem {
    @apply text-gray-400 hover:text-gray-800 text-xl py-4 cursor-pointer;
}

.navItemActive {
    @apply text-blue-600 hover:text-blue-700; 
}

.tooltip {
    @apply absolute w-auto min-w-max left-16 text-base font-medium hidden;
}

.bottomWrapper {
    @apply flex flex-col justify-between items-center;
}

.notifications {
    @apply w-10 h-10 bg-gray-100 hover:bg-gray-200 cursor-pointer rounded-xl flex items-center justify-center text-gray-800 text-lg relative mb-4;
}

.badge {
    @apply h-5 w-5 flex justify-center items-center text-white absolute -top-1 -right-1 bg-red-500 text-xs rounded-full;
}

.settingsLogo {
    @apply text-3xl text-gray-400 hover:text-gray-800 cursor-pointer;
}
Enter fullscreen mode Exit fullscreen mode

Our component will receive only one prop which will be the navigation data (routes) that were defined previously. After that we will use the useState hook to define the selected route (the initial route will be Home). Next we have to create a function that will have a switch statement, which will be used to return the indicated icon according to the element of the array.

// @src/components/Sidebar.jsx
import React, { useState, useCallback } from "react";
import { IoLogoEdge, IoBookmark } from "react-icons/io5";
import {
  BsImageFill,
  BsFillHandbagFill,
  BsFillStarFill,
  BsHouseFill,
} from "react-icons/bs";
import { RiSettings4Fill } from "react-icons/ri";
import { FaRegBell } from "react-icons/fa";
import classNames from "classnames";

import styles from "./Sidebar.module.css";

const Sidebar = ({ navigationData }) => {
  const [currentRoute, setCurrentRoute] = useState("Home");

  const renderIcon = useCallback((element) => {
    switch (element) {
      case "Home":
        return <BsHouseFill />;
      case "Gallery":
        return <BsImageFill />;
      case "Store":
        return <BsFillHandbagFill />;
      case "Favorites":
        return <BsFillStarFill />;
      case "Saved":
        return <IoBookmark />;
    }
  }, []);

  return (
    <nav className={styles.wrapper}>
      <span className={styles.logo}>
        <IoLogoEdge />
      </span>
      <ul className={styles.navListItems}>
        {navigationData.map((element, index) => (
          <li
            key={index}
            className={classNames([
              styles.navItem,
              currentRoute === element && styles.navItemActive,
              "group",
            ])}
            onClick={() => setCurrentRoute(element)}
          >
            {renderIcon(element)}
            <span
              className={classNames([styles.tooltip, "group-hover:inline"])}
            >
              {element}
            </span>
          </li>
        ))}
      </ul>
      <div className={styles.bottomWrapper}>
        <div className={styles.notifications}>
          <span className={styles.badge}>24</span>
          <FaRegBell />
        </div>
        <span className={styles.settingsLogo}>
          <RiSettings4Fill />
        </span>
      </div>
    </nav>
  );
};

export default Sidebar;
Enter fullscreen mode Exit fullscreen mode

Last but not least we have to go to our entry file (which in this case is App.jsx) and we will have the following styles:

/* @src/App.module.css */

.container {
  @apply bg-gray-200;
}

.devLogo {
  @apply flex items-center justify-center text-5xl text-gray-300 h-screen;
}
Enter fullscreen mode Exit fullscreen mode

Now in our App.jsx we will import our navigation data and our Sidebar component that we created, then we will pass the indicated props.

// @src/App.jsx
import React from "react";
import { FaDev } from "react-icons/fa";

import styles from "./App.module.css";
import Sidebar from "./components/Sidebar";
import navigationData from "./data/navigation";

const App = () => {
  return (
    <div className={styles.container}>
      <Sidebar navigationData={navigationData} />
      <div className={styles.devLogo}>
        <FaDev />
      </div>
    </div>
  );
};

export default App;
Enter fullscreen mode Exit fullscreen mode

Conclusion

As always, I hope you found it interesting. If you noticed any errors in this article, please mention them in the comments. šŸ§‘šŸ»ā€šŸ’»

Hope you have a great day! šŸ™Œ

Discussion (8)

Collapse
jt3k profile image
Andrey Gurtovoy

my opinion: this is an article that could help popularize tailwind. because tailwind itself is rapidly losing its popularity. not surprising since this is a reinvention of atomic-css which has already proven everything.

Collapse
ceoshikhar profile image
Shikhar Sharma

Hoping to get the same traction as your "Navbar" post? My best wishes to you.

Collapse
franciscomendes10866 profile image
Francisco Mendes Author

I have never published a single article hoping to get some traction. I just look at something and think "I think it would be fun to share it with others".

I don't make money from it, so "popularity" doesn't matter. āœŒļø

Collapse
ceoshikhar profile image
Shikhar Sharma

Only few people like you are so brave that they don't care or want their work to get any recognition. My respect.

Thread Thread
franciscomendes10866 profile image
Francisco Mendes Author • Edited on

I learned what I know on the internet, completely free of charge. Now it's my turn to give back what I know for free too. If I help at least one person with my simple articles, it makes me happy.

Thank you and have a nice day šŸ¤™

Thread Thread
ceoshikhar profile image
Shikhar Sharma

Funny how you mentioned money twice yet I never even mentioned it once.

Collapse
flaszer_cb6403ed69 profile image
Damien

Any particular reason why the navigationData prop does not include the icon along the title already?

Collapse
franciscomendes10866 profile image
Francisco Mendes Author

To be honest no šŸ˜…, it's just an approach I like to take. Now you can adapt it your way. šŸ’Ŗ