Back to roadmaps lucide-icons Course

Project: Collapsible Sidebar Navigation

In this project, we will construct a collapsible administrative sidebar component. The component supports toggleable expanded states and highlights active menu items using Lucide icons.


1. Sidebar Specifications

  • Expanded State: Displays full menu text alongside icons.
  • Collapsed State: Shrinks to a narrow column showing only the icons.
  • Tooltips: Shows menu titles on hover when the sidebar is collapsed.

2. Implementing the React Component

Here is the React component code. Save this inside src/components/Sidebar.tsx:

import React, { useState } from "react";
import { 
  Home, 
  BarChart2, 
  Settings, 
  ChevronLeft, 
  ChevronRight, 
  Users 
} from "lucide-react";

interface MenuItem {
  title: string;
  icon: React.ComponentType<{ className?: string }>;
  active: boolean;
}

export function Sidebar() {
  const [isExpanded, setIsExpanded] = useState(true);

  const menuItems: MenuItem[] = [
    { title: "Dashboard", icon: Home, active: true },
    { title: "Analytics", icon: BarChart2, active: false },
    { title: "Team Members", icon: Users, active: false },
    { title: "Configuration", icon: Settings, active: false },
  ];

  return (
    <aside 
      className={`min-h-screen bg-slate-900 text-slate-100 flex flex-col transition-all duration-300 border-r border-slate-800 ${
        isExpanded ? "w-64" : "w-20"
      }`}
    >
      {/* 1. Header with Collapse Toggle button */}
      <div className="h-16 flex items-center justify-between px-4 border-b border-slate-800">
        {isExpanded && <span className="font-bold text-lg">Admin Panel</span>}
        <button 
          onClick={() => setIsExpanded(!isExpanded)}
          className="p-1.5 rounded-lg bg-slate-800 hover:bg-slate-700 transition mx-auto md:mx-0"
        >
          {isExpanded ? <ChevronLeft className="w-5 h-5" /> : <ChevronRight className="w-5 h-5" />}
        </button>
      </div>

      {/* 2. Menu Items Navigation Links */}
      <nav className="flex-1 p-3 space-y-2 mt-4">
        {menuItems.map((item, index) => {
          const Icon = item.icon;
          return (
            <a
              key={index}
              href="#"
              className={`flex items-center gap-4 px-4 py-3 rounded-xl transition-all group relative ${
                item.active 
                  ? "bg-blue-600 text-white font-semibold" 
                  : "text-slate-400 hover:bg-slate-800 hover:text-white"
              }`}
            >
              {/* Icon */}
              <Icon className="w-5 h-5 shrink-0" />

              {/* Text Label (Hidden if sidebar collapsed) */}
              {isExpanded ? (
                <span className="truncate">{item.title}</span>
              ) : (
                /* Simple CSS Tooltip for collapsed mode */
                <span className="absolute left-16 scale-0 group-hover:scale-100 transition-all bg-slate-950 text-white text-xs px-2.5 py-1.5 rounded-md border border-slate-800 shadow-md z-30 whitespace-nowrap">
                  {item.title}
                </span>
              )}
            </a>
          );
        })}
      </nav>

      {/* 3. Footer version stamp */}
      <div className="p-4 border-t border-slate-800 text-xs text-slate-500 text-center">
        {isExpanded ? "System Version 2.0" : "v2.0"}
      </div>
    </aside>
  );
}

This sidebar uses Tailwind conditional template classes (such as w-64 and w-20) to handle width transitions smoothly when the user toggles the collapse button.

Published on Last updated: