How to Create fully Responsive React Tailwind Sidebar with Dropdowns

alt
Max Gadget
October 15, 2022
-
1 Mins Read
Share

I have been using Tailwind CSS in most of my recent projects and I love how easy it is. However, if we compare it to bootstrap or other frameworks, it lacks base components that can help build sites faster. So, I tried to build components from scratch. Here is how I achieved creating a responsive sidebar with the dropdown in React and tailwind CSS.


Here is how the component will look on different platforms like PC, tablets, and mobile phones.

MaxGadget Blog


So, as you can see, I have created a floating button that is used to Show and Hide the sidebar component on smaller screens.

<button
        className="fixed lg:hidden z-90 bottom-10 right-8 bg-teal-800 w-10 h-10 rounded-full drop-shadow-lg flex justify-center items-center text-white text-4xl hover:bg-teal-800   duration-300"
        onClick={toggleSidebar}
      >
        <span class="text-white">
          <svg
            xmlns="http://www.w3.org/2000/svg"
            fill="currentColor"
            class="w-6 m-auto"
            viewBox="0 0 16 16"
          >
            <path
              fill-rule="evenodd"
              d="M3.646 9.146a.5.5 0 0 1 .708 0L8 12.793l3.646-3.647a.5.5 0 0 1 .708.708l-4 4a.5.5 0 0 1-.708 0l-4-4a.5.5 0 0 1 0-.708zm0-2.292a.5.5 0 0 0 .708 0L8 3.207l3.646 3.647a.5.5 0 0 0 .708-.708l-4-4a.5.5 0 0 0-.708 0l-4 4a.5.5 0 0 0 0 .708z"
            />
          </svg>
        </span>
      </button>



Now that we have created the floating button, we can move next to create the sidebar component. The sidebar component is going to have a dropdown menu, so I have created a menu links route with the appropriate icons. By mapping the menus array we can add the menu to the sidebar.

const Menus = [
  { title: 'Dashboard', src: 'Chart_fill', icon: <MdOutlineDashboard /> },
  { title: 'Inbox', src: 'Chat', icon: <BsChatLeftText /> },
  { title: 'Accounts', src: 'User', gap: true, icon: <MdAccountCircle /> },
  { title: 'Schedule ', src: 'Calendar', icon: <BsCalendarCheck /> },
  {
    title: 'Services',
    src: 'Services',
    icon: <BsServer />,
    subMenus: [
      {
        title: 'Service 1',
        src: '/services/services1',

        cName: 'sub-nav',
      },
      {
        title: 'Service 2',
        src: '/services/services2',

        cName: 'sub-nav',
      },
      {
        title: 'Service 3',
        src: '/services/services3',
      },
    ],
  },
  { title: 'Analytics', src: 'Chart', icon: <MdAnalytics /> },
  { title: 'Files ', src: 'Folder', gap: true, icon: <BsFiles /> },
  { title: 'Setting', src: 'Setting', icon: <MdOutlineSettings /> },
  { title: 'Logout', src: 'Logout', icon: <MdLogout /> },
];



Here is how the sidebar.jsx file looks like :

import React, { useState } from 'react';
import {
  MdOutlineDashboard,
  MdAccountCircle,
  MdAnalytics,
  MdOutlineSettings,
  MdLogout,
} from 'react-icons/md';
import {
  BsChevronDown,
  BsChatLeftText,
  BsCalendarCheck,
  BsFiles,
  BsServer,
} from 'react-icons/bs';

const Menus = [
  { title: 'Dashboard', src: 'Chart_fill', icon: <MdOutlineDashboard /> },
  { title: 'Inbox', src: 'Chat', icon: <BsChatLeftText /> },
  { title: 'Accounts', src: 'User', gap: true, icon: <MdAccountCircle /> },
  { title: 'Schedule ', src: 'Calendar', icon: <BsCalendarCheck /> },
  {
    title: 'Services',
    src: 'Services',
    icon: <BsServer />,
    subMenus: [
      {
        title: 'Service 1',
        src: '/services/services1',

        cName: 'sub-nav',
      },
      {
        title: 'Service 2',
        src: '/services/services2',

        cName: 'sub-nav',
      },
      {
        title: 'Service 3',
        src: '/services/services3',
      },
    ],
  },
  { title: 'Analytics', src: 'Chart', icon: <MdAnalytics /> },
  { title: 'Files ', src: 'Folder', gap: true, icon: <BsFiles /> },
  { title: 'Setting', src: 'Setting', icon: <MdOutlineSettings /> },
  { title: 'Logout', src: 'Logout', icon: <MdLogout /> },
];

const Sidebar = () => {
  const [open, setOpen] = useState(true);
  const [subMenuOpen, setSubMenuOpen] = useState(false);
  const toggleSidebar = () => {
    setOpen(!open);
  };
  return (
    <div className=" h-screen flex items-end justify-end ">
      <button
        className="fixed lg:hidden z-90 bottom-10 right-8 bg-teal-800 w-10 h-10 rounded-full drop-shadow-lg flex justify-center items-center text-white text-4xl hover:bg-teal-800   duration-300"
        onClick={toggleSidebar}
      >
        <span class="text-white">
          <svg
            xmlns="http://www.w3.org/2000/svg"
            fill="currentColor"
            class="w-6 m-auto"
            viewBox="0 0 16 16"
          >
            <path
              fill-rule="evenodd"
              d="M3.646 9.146a.5.5 0 0 1 .708 0L8 12.793l3.646-3.647a.5.5 0 0 1 .708.708l-4 4a.5.5 0 0 1-.708 0l-4-4a.5.5 0 0 1 0-.708zm0-2.292a.5.5 0 0 0 .708 0L8 3.207l3.646 3.647a.5.5 0 0 0 .708-.708l-4-4a.5.5 0 0 0-.708 0l-4 4a.5.5 0 0 0 0 .708z"
            />
          </svg>
        </span>
      </button>

      <div
        className={` ${
          open ? 'w-48 px-2 ' : 'w-0 '
        } lg:w-72 bg-teal-800 h-screen   relative duration-500`}
      >
        <div className=" justify-center mt-3">
          <h1
            className={`text-white  font-medium text-2xl text-center duration-200 ${
              !open && 'invisible'
            }`}
          >
            LOGO
          </h1>
        </div>
        <ul className="pt-6">
          {Menus.map((Menu, index) => (
            <>
              <li
                key={index}
                className={`flex  rounded-md p-2 cursor-pointer hover:bg-teal-400 text-white text-sm items-center gap-x-4 
              ${Menu.gap ? 'mt-9' : 'mt-2'}  `}
              >
                {Menu.icon ? Menu.icon : <MdOutlineDashboard />}
                <span className="flex-1">{Menu.title}</span>
                {Menu.subMenus && (
                  <BsChevronDown
                    onClick={() => setSubMenuOpen(!subMenuOpen)}
                    className={`${subMenuOpen && 'rotate-180'}`}
                  />
                )}
              </li>
              {Menu.subMenus && subMenuOpen && open && (
                <ul>
                  {Menu.subMenus.map((subMenuItem, idx) => (
                    <li
                      key={idx}
                      className="flex px-5 cursor-pointer text-center text-sm text-gray-200 py-1"
                    >
                      {subMenuItem.title}
                    </li>
                  ))}
                </ul>
              )}
            </>
          ))}
        </ul>
      </div>
    </div>
  );
};

export default Sidebar;

You can get the full source code from the Github Link.