How to Create a Side Navigation Bar using React and Tailwind
Francisco Mendes
Posted on November 6, 2021
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:
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
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"];
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;
}
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;
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;
}
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;
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! 🙌
Posted on November 6, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.