Build a Modern Dashboard Side Navigation Bar in ReactJS using TailwindCss only
Tools Needed:
Visual Studio Code (preferably)
Nodejs installed
Creating your React app using Vite:
For a faster installation of the react app, we make use of vite rather than the contemporary create-react app.
npm create vite@latest dashboard -- --template react
After the successful progress of the code above, simply install the app by running these commands
cd dashboard
npm i
Installing the requisite packages:
In order to speed up the process of development we will install the following packages:
npm i react-icons react-router-dom --legacy-peer-deps
Creating The Dashboard Layout:
import React, from "react";
const DashboardLayout= () => {
return <div className="w-full">
{/* sidebar section */}
{/* main outlet */}
</div>;
};
Explanation:
So in the above code, we created a functional component, which is a function that returns a react component. It is expecting a sidebar component and the main outlet.
In the returned section, you can see HTML content with a kind of inbuilt CSS. The essence of using React is that it provides us room for writing HTML, and CSS inside javascript in one file.
How does React achieve such a feat? It does so with the aid of JSX. You see JSX allows this feat of writing HTML and CSS in a javascript file.
At the moment we are just having a black page. So let's proceed to the next steps of creating our sidebar component
Creating The Sidebar Component:
For us to create a sidebar component, We have to create a folder in the root directory called components. So in the components folder created we create a file called DashboardSidebar.jsx.
const DashboardSidebar = () => {
return (
<div
className={`w-[100px] flex flex-col gap-2`}
>
</div>
);
};
Explanation:
So in the code above, we created a functional component, which returns a div. We are also making use of tailwind classes. You can see:
className={`w-[100px] flex flex-col gap-2`}
What this shows is that we are setting the width to 100px, setting the container to a flex container, and also making the flex orientation to be column-wise.
Importing Sidebar Component:
So we have to introduce the sidebar component, into the dashboard layout. Else without doing, we will not see the content of the sidebar
import React, from "react";
import DashboardSidebar from './components/DashboardSidebar'
const DashboardLayout= () => {
return <div className="w-full">
{/* sidebar section */}
<DashboardSidebar/>
{/* main outlet */}
</div>;
};
Sidebar Component Styling:
We are making progress! As you can see the sidebar components has an empty content. So lets make further progress in styling the container.
const DashboardSidebar = () => {
return (
<div className={`w-full flex column sticky bg-[#fafafa] top-0 h-screen gap-2`}>
<div className="w-full h-full py-4 justify-between flex items-center flex-col gap-4">
{/* top content */}
{/* center content */}
</div>
</div>
);
};
Explanation:
So we added additional styles to the parent div, which is the first div, to be sticky, to take the screen height, and to start at the top.
In the second div, we intend it to take the height , width of its parent (the first div). To also have a flex container, items ( its children) should be centerly place, and also making the flex orientation to be column-wise. We also set its background to be alittle bit light grey.
We added comment to guide us in placing the right element, in their correct position.
Top content development:
In the section where top content is commented, we will write out its HTML content.
const DashboardSidebar = () => {
return (
<div className={`w-full flex column bg-[#fafafa] sticky top-0 h-screen gap-2`}>
<div className="w-full h-full py-4 justify-between flex items-center flex-col gap-4">
{/* top content */}
<div className="">
<Link
to={"/"}
className=""
>
<img
loading="lazy"
src="https://www.hopper.com/assets/treasure-D-5S8iOp.svg"
className=""
/>
</Link>
</div>
{/* center content */}
</div>
</div>
);
};
So we added few HTML element and react element, Such as the div, the LINK element and the img HTML element.
Top content Styling:
The top content does not look alright so we have to add some tailwind utilities classes, to the top content.
const DashboardSidebar = () => {
return (
<div className={`w-full flex column bg-[#fafafa] sticky top-0 h-screen gap-2`}>
<div className="w-full h-full py-4 justify-between flex items-center flex-col gap-4">
{/* top content */}
<div className="px-4 w-full">
<Link
to={"/"}
className="w-full flex items-center"
>
<img
loading="lazy"
src="https://www.hopper.com/assets/treasure-D-5S8iOp.svg"
className="w-14 object-cover"
/>
</Link>
</div>
{/* center content */}
</div>
</div>
);
};
Explanation:
So for the parent div, we added these classes:
px-4: To make the top content parent div to have a padding of 1rem to both the right and left side of the container
w-full: To also make the parent container to take the full width of the sidebar
So also for the Link element we make it to take the full width of the parent container and also placing the item to be center in the vertical axis of the container.
For the image it should take a width of 3.5rem and it should also be object covered.
Now that we are done with the top content, let us head onto the center content of the dashboard sidebar.
Center content development:
The center content will have several links. In order to make our Dashboardsidebar components to be neat, we have to create another component called NavItems.
const NavItems = ({items}) => {
return (
<div className={`w-full`}>
</div>
);
};
So the NavItems component, is functional component which is expecting a react prop named as Items.
So we have to import NavItems component to the DashboardSidebar component. and setup the necessary data
import NavItems from './NavItems'
const DashboardSidebar = () => {
return (
<div className={`w-full flex column sticky bg-[#fafafa] top-0 h-screen gap-2`}>
<div className="w-full h-full py-4 justify-between flex items-center flex-col gap-4">
{/* top content */}
<div className="px-4 w-full">
<Link
to={"/"}
className="w-full flex items-center"
>
<img
loading="lazy"
src="https://www.hopper.com/assets/treasure-D-5S8iOp.svg"
className="w-14 object-cover"
/>
</Link>
</div>
{/* center content */}
<NavItems/>
{/* bottom content */}
</div>
</div>
);
};
The Navitems is expecting a prop, which is a an object entity.
Navlinks data :
This is just an array of objects with keys such as title, path, icon. We also have to create a data folder in the src folder, which will contain a file called index.jsx. This is were the Navlinks data will be exported from:
import { FaRegUser, FaMoneyBill } from "react-icons/fa";
import { BiFoodMenu, BiMessage } from "react-icons/bi";
import { LayoutDashboard } from "lucide-react";
import { MdRateReview } from "react-icons/md";
export const Navlinks = [
{
title: "Dashboard",
path: "",
icon: <LayoutDashboard fontSize={"20px"} />,
},
{
icon: <BiFoodMenu fontSize={"20px"} />,
title: "Menu",
path: "/menu",
},
{
icon: <FaMoneyBill fontSize={"20px"} />,
title: "Transactions",
path: "/orders",
},
{
icon: <MdRateReview fontSize={"20px"} />,
title: "Reviews",
path: "/review",
},
{
icon: <BiMessage fontSize={"20px"} />,
title: "Messages",
path: "/message",
},
{
icon: <FaRegUser fontSize={"18px"} />,
title: "Clients",
path: "/customers",
},
];
Now that the Navlinks data items has been created, we then have to export to the NavItems component
import {Navlinks} from '../data'
import NavItems from './NavItems'
const DashboardSidebar = () => {
return (
<div className={`w-full flex column sticky bg-[#fafafa] top-0 h-screen gap-2`}>
<div className="w-full h-full py-4 justify-between flex items-center flex-col gap-4">
{/* top content */}
<div className="px-4 w-full">
<Link
to={"/"}
className="w-full flex items-center"
>
<img
loading="lazy"
src="https://www.hopper.com/assets/treasure-D-5S8iOp.svg"
className="w-14 object-cover"
/>
</Link>
</div>
{/* center content */}
{Navlinks.map((items, index)=> {
console.log(items)
return <NavItems items={items} key={index}/>
})}
{/* bottom content */}
</div>
</div>
);
};
Explanation:
As you can see in the above, we have to map our Navlinks data, and pass each objects as props into the NavItems components.
If you console.log() the value of the items you will see a series object with keys and values matching the Navlinks data.
So till now, nothing has been displayed and the necessary styles has not yet been applied. So let's proceed further in displaying and styling the NavItems component
NavItems development:
import { NavLink } from "react-router-dom";
const NavItems = ({ Items }) => {
return (
<div className="w-full">
<NavLink
end
className={`group tab relative bg-[#fafafa] text-base w-[90%] mx-auto`}
to={`/dashboard${Items.path}`}
>
<div className="flex w-full justify-center relative items-center">
<span className="w-12 h-12 text-base rounded-xl flex items-center text-blue justify-center">
{" "}
{Items.icon}
</span>
</div>
// title
</NavLink>
</div>
);
};
Explanation:
We added a NavLink, which is a react-router-dom element. It is more flexible that the Link property due to we easily detect which link is active based on the navigated page. So we added various tailwind utilities classes to it, such as:
group: This class tells tailwind that the initial effect of an action originates from. Such as when you hover around an element, you can pass the effect to the neighbouring element, but tailwind notes that the effect stems form the element that has the className group.
relative: We use this tailwind utility class to give an idea that the element has a position of relative
text-base: A tailwind class that represent 16px for font-size.
w-[90%], mx-auto: The width should be 90%, and it should be aligned as the center.
For the subsequent div and span, we just gave it a width and height of 48px, it should have a border-radius of 20px, and also positioned the element to be both center in the x and y axis of the container. The Icon element was then displayed.
Now the next trick, is it to display the title only when we hover along the Navlink. It should move a little slightly to the top and it should also scale ( from a small scale to its original size)
import { Link, NavLink } from "react-router-dom";
const NavItems = ({ Items }) => {
return (
<div className="w-full">
<div className="w-[100%] family5 font-normal text-sm mx-auto">
<NavLink
end
className={`group tab relative text-base w-[90%] mx-auto`}
to={`/dashboard${Items.path}`}
>
<div className="flex w-full md:justify-center items-center">
<span className="w-12 h-12 text-base rounded-xl flex items-center text-blue justify-center">
{" "}
{Items.icon}
</span>
</div>
<div
className="absolute text-sm group-hover:opacity-1
opacity-0 top-[55%] group-hover:top-[25%] block px-4
py-2 bg-[#000] text-[#fff] rounded-[40px] left-[140%]"
>
{Items?.title}
</div>
</NavLink>
</div>
</div>
);
};
Explanation:
We have now added the style and the element. But now, you will be amazed by the outcome. Well I will explain the effect and the reason for these utilities classes
className="absolute left-[140%] top-[55%] opacity-0
group-hover:top-[25%] group-hover:opacity-1 block px-4 text-sm
py-2 bg-[#000] text-[#fff] rounded-[40px]"
absolute: We have to set the position of the element to be absolute in reference to the NavLink
left-[140%], top-[55%], opacity-0: We had to align the span to start 140% away from the dashboard with reference to the NavLink and should also be positioned 55% from the top of the NavLink. It should also have a opacity of 0.
group-hover:top-[25%], group-hover:opacity-1: So we back to the essence of the group class. So in essence, we are saying that when we hover along the Navlink, the opacity of the div should go to 1 since it was 0 initially. And also, it should Move upward to 25%, since 55% form the top is far greater than 25%.
rounded-[40px],text-sm, text-[#fff], bg-[#000], px-4, py-2, block: This classes intends to make the padding to the x-axis to be 1rem and to the y-axis to .5rem. We also intend to make the element to have a display of block, a color of white and font-size of 14px.
So finally, we have achieved this dashboard sidebar, which takes a little leap from the contemporary sidebar.
If you have any queries concerning this or any other programming problems, please make them through the comments, I’d be happy to help. If you have any ways to make this code better, I will earnestly appreciate you effort. Thank you!
Subscribe to my newsletter
Read articles from Victor Essien directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Victor Essien
Victor Essien
As an experienced software developer with over 4 years of experience in software development; Seeking the philosopher stone has always been my drive in whatever I do, and software development is not left out of the picture. I am constantly aware of the rapid change of wave flow in software development. This continually reminds me of the need to learn every day to keep up with these changes in software development. My lifelong principle in software development is that there is always a solution to a problem. I earnestly believe in this approach (or you can view it as a mindset) when approaching a new problem that seems daunting. I don't settle with the view that nothing can be solved; So in software development when faced with a stifling task, I seek means for a solution to that problem no matter how it will take me. In all of this, I see myself as someone who is a dedicated hard-working software developer who is constantly striving to improve my skills and knowledge in the field. I always put my client in focus when developing applications that will fill in the needs of their quest.