Sidebar
Component
Premium Tailwind sidebar components featuring glassmorphism, fluid collapsibility, and nested Tailwind CSS sidebar menus.
Install via CLI
Run this command to automatically add the component and its dependencies to your project.
npx @abhaysinghr516/business-wish add sidebarNew to the CLI? Run
npx @abhaysinghr516/business-wish init first to initialize your project.For complex applications and dashboards, a robust Tailwind sidebar provides the structural backbone necessary for deep navigation. These components feature seamless transitions, collapsible states, and organized Tailwind CSS sidebar menus built with premium, ultra-minimal aesthetics.
A strong sidebar is often paired with a top-level Header for global actions, and frequently utilizes an Avatar at the bottom to represent the current user's profile.
Basic Sleek Sidebar
import React, { useState } from "react";
const BasicSidebar = () => {
const [activeItem, setActiveItem] = useState("Dashboard");
return (
<div className="flex flex-col w-64 bg-white dark:bg-neutral-950 h-screen justify-between border-r border-neutral-200/50 dark:border-white/10 shadow-[4px_0_24px_rgba(0,0,0,0.02)] dark:shadow-[4px_0_24px_rgba(0,0,0,0.2)]">
<div className="overflow-y-auto pt-6 px-4">
<div className="flex items-center px-4 mb-8">
<div className="w-7 h-7 bg-neutral-900 dark:bg-white rounded-lg flex items-center justify-center mr-3 shadow-sm">
<span className="text-white dark:text-neutral-900 font-bold text-[14px]">A</span>
</div>
<span className="font-semibold text-[16px] text-neutral-900 dark:text-white tracking-tight">
Acme Inc.
</span>
</div>
<div className="space-y-1 mt-6">
<p className="px-4 text-[11px] font-semibold text-neutral-400 uppercase tracking-wider mb-2">Platform</p>
{["Dashboard", "Projects", "Team", "Reports", "Settings"].map((item) => (
<button
key={item}
className={`w-full flex items-center px-4 py-2.5 text-[14px] font-medium rounded-xl transition-all duration-200 border border-transparent ${
activeItem === item
? "bg-neutral-100 dark:bg-neutral-900 text-neutral-900 dark:text-white shadow-sm border-neutral-200/50 dark:border-white/5"
: "text-neutral-600 dark:text-neutral-400 hover:bg-neutral-50 dark:hover:bg-neutral-900/50"
}`}
onClick={() => setActiveItem(item)}
>
{item}
</button>
))}
</div>
</div>
<div className="p-4 mx-4 mb-4 mt-auto">
<button className="w-full flex items-center gap-3 p-2 hover:bg-neutral-100 dark:hover:bg-neutral-900 rounded-xl transition-colors">
<img
className="object-cover rounded-full h-9 w-9 border border-neutral-200 dark:border-neutral-800 shadow-sm"
src="https://i.pravatar.cc/150?img=32"
alt="avatar"
/>
<div className="flex flex-col text-left">
<span className="text-[14px] font-semibold text-neutral-900 dark:text-white leading-tight">Sarah J.</span>
<span className="text-[12px] text-neutral-500">sarah@acme.com</span>
</div>
</button>
</div>
</div>
);
};
export default BasicSidebar;
Sidebar with Elegant Icons
import React, { useState } from "react";
import { Search, Home, LayoutDashboard, FolderOpen, Users, MessageSquare, PieChart, Settings } from "lucide-react";
const SidebarwithIcons = () => {
const [activeItem, setActiveItem] = useState("Home");
const menuItems = [
{ name: "Home", icon: Home },
{ name: "Dashboard", icon: LayoutDashboard },
{ name: "Projects", icon: FolderOpen },
{ name: "Team", icon: Users },
{ name: "Messages", icon: MessageSquare },
{ name: "Analytics", icon: PieChart },
];
return (
<div className="flex flex-col w-[260px] bg-neutral-50/50 dark:bg-[#0A0A0A] h-screen justify-between border-r border-neutral-200/60 dark:border-white/10">
<div className="overflow-y-auto px-4 py-6">
<div className="mb-6 relative">
<Search className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-neutral-400" />
<input
type="text"
placeholder="Search..."
className="w-full bg-white dark:bg-neutral-900 border border-neutral-200 dark:border-neutral-800 rounded-xl py-2 pl-9 pr-4 text-[13px] outline-none focus:ring-2 focus:ring-neutral-200 dark:focus:ring-neutral-800 shadow-sm transition-all"
/>
</div>
<nav className="space-y-1.5">
{menuItems.map((item) => {
const isActive = activeItem === item.name;
return (
<button
key={item.name}
onClick={() => setActiveItem(item.name)}
className={`w-full group flex items-center justify-between px-3 py-2.5 rounded-xl transition-all duration-300 ${
isActive
? "bg-white dark:bg-neutral-900 shadow-sm border border-neutral-200/60 dark:border-white/10"
: "hover:bg-neutral-100 dark:hover:bg-neutral-900 border border-transparent"
}`}
>
<div className="flex items-center gap-3">
<item.icon
className={`w-4 h-4 transition-colors duration-300 ${
isActive ? "text-neutral-900 dark:text-white" : "text-neutral-500 group-hover:text-neutral-700 dark:group-hover:text-neutral-300"
}`}
strokeWidth={isActive ? 2.5 : 2}
/>
<span className={`text-[14px] font-medium transition-colors ${
isActive ? "text-neutral-900 dark:text-white" : "text-neutral-600 dark:text-neutral-400 group-hover:text-neutral-900 dark:group-hover:text-white"
}`}>
{item.name}
</span>
</div>
{item.name === "Messages" && (
<span className="bg-blue-500 text-white text-[10px] font-bold px-1.5 py-0.5 rounded-full">3</span>
)}
</button>
)
})}
</nav>
</div>
<div className="p-4 border-t border-neutral-200/60 dark:border-white/10">
<button className="w-full group flex items-center gap-3 px-3 py-2.5 rounded-xl hover:bg-neutral-100 dark:hover:bg-neutral-900 transition-colors">
<Settings className="w-4 h-4 text-neutral-500 group-hover:text-neutral-700 dark:group-hover:text-neutral-300" strokeWidth={2} />
<span className="text-[14px] font-medium text-neutral-600 dark:text-neutral-400 group-hover:text-neutral-900 dark:group-hover:text-white">Settings</span>
</button>
</div>
</div>
);
};
export default SidebarwithIcons;
Floating Island Sidebar
import React, { useState } from "react";
import { LayoutDashboard, PieChart, Users } from "lucide-react";
const FloatingIslandSidebar = () => {
const [activeItem, setActiveItem] = useState("Layout");
const menuItems = [
{ name: "Layout", icon: LayoutDashboard },
{ name: "Analytics", icon: PieChart },
{ name: "Community", icon: Users },
];
return (
<div className="h-screen bg-neutral-100 dark:bg-neutral-950 p-4 flex">
<div className="flex flex-col w-[260px] bg-white/70 dark:bg-neutral-900/70 backdrop-blur-2xl border border-white dark:border-white/10 rounded-[28px] shadow-xl overflow-hidden h-full">
<div className="p-6 pb-2">
<div className="flex items-center gap-3">
<div className="w-8 h-8 rounded-full bg-gradient-to-tr from-rose-500 to-orange-400 shadow-inner" />
<span className="font-bold text-[15px] tracking-tight text-neutral-900 dark:text-white">Nexus</span>
</div>
</div>
<div className="flex-1 overflow-y-auto p-4 space-y-2">
{menuItems.map((item) => (
<button
key={item.name}
onClick={() => setActiveItem(item.name)}
className={`w-full flex items-center gap-3 px-4 py-3 rounded-2xl transition-all duration-300 ${
activeItem === item.name
? "bg-neutral-900 dark:bg-white text-white dark:text-neutral-900 shadow-md scale-[0.98]"
: "bg-transparent text-neutral-600 dark:text-neutral-400 hover:bg-white/50 dark:hover:bg-neutral-800/50"
}`}
>
<item.icon className="w-[18px] h-[18px]" strokeWidth={activeItem === item.name ? 2.5 : 2} />
<span className="text-[14px] font-semibold">{item.name}</span>
</button>
))}
</div>
<div className="p-4 mt-auto">
<div className="bg-neutral-100 dark:bg-neutral-950/50 rounded-2xl p-4 flex items-center justify-between border border-neutral-200/50 dark:border-white/5">
<div className="flex flex-col items-start gap-1">
<span className="text-[12px] font-bold text-neutral-900 dark:text-white">Pro Plan</span>
<span className="text-[11px] text-neutral-500">4 days left</span>
</div>
<button className="text-[11px] font-semibold bg-white dark:bg-neutral-800 px-2 py-1 rounded-lg shadow-sm border border-neutral-200 dark:border-white/5">Upgrade</button>
</div>
</div>
</div>
</div>
);
};
export default FloatingIslandSidebar;
Expandable Nested Sidebar
import React, { useState } from "react";
import { Home, Bell, FolderOpen, Users, ChevronDown } from "lucide-react";
const ExpandableNestedSidebar = () => {
const [activeItem, setActiveItem] = useState("Overview");
const [openGroups, setOpenGroups] = useState({
Projects: true
});
const toggleGroup = (group) => {
setOpenGroups(prev => ({ ...prev, [group]: !prev[group] }));
};
const menuStructure = [
{ type: 'item', name: "Overview", icon: Home },
{ type: 'item', name: "Notifications", icon: Bell, badge: 2 },
{ type: 'divider' },
{
type: 'group',
name: "Projects",
icon: FolderOpen,
items: ["Design System", "Marketing Site", "Mobile App"]
},
{
type: 'group',
name: "Team",
icon: Users,
items: ["Developers", "Designers", "Management"]
}
];
return (
<div className="flex flex-col w-[260px] bg-white dark:bg-[#0A0A0A] h-screen border-r border-neutral-200/60 dark:border-white/10 shadow-sm">
<div className="p-6">
<h2 className="text-[18px] font-semibold text-neutral-900 dark:text-white tracking-tight">Workspace</h2>
</div>
<div className="flex-1 overflow-y-auto px-4 space-y-1">
{menuStructure.map((node, i) => {
if (node.type === 'divider') {
return <div key={i} className="h-px w-full bg-neutral-200/60 dark:bg-neutral-800/60 my-4" />
}
if (node.type === 'item') {
const isActive = activeItem === node.name;
return (
<button
key={node.name}
onClick={() => setActiveItem(node.name)}
className={`w-full flex items-center justify-between px-3 py-2 rounded-lg transition-colors ${
isActive ? "bg-blue-50 dark:bg-blue-500/10 text-blue-600 dark:text-blue-400 font-medium" : "text-neutral-600 dark:text-neutral-400 hover:bg-neutral-100 dark:hover:bg-neutral-900"
}`}
>
<div className="flex items-center gap-3">
<node.icon className="w-4 h-4" />
<span className="text-[14px]">{node.name}</span>
</div>
{node.badge && <span className="bg-blue-100 dark:bg-blue-500/20 text-blue-600 dark:text-blue-400 text-[10px] font-bold px-1.5 py-0.5 rounded-full">{node.badge}</span>}
</button>
)
}
if (node.type === 'group') {
const isOpen = openGroups[node.name];
return (
<div key={node.name} className="pt-2">
<button
onClick={() => toggleGroup(node.name)}
className="w-full flex items-center justify-between px-3 py-2 text-neutral-600 dark:text-neutral-400 hover:bg-neutral-100 dark:hover:bg-neutral-900 rounded-lg transition-colors group"
>
<div className="flex items-center gap-3">
<node.icon className="w-4 h-4" />
<span className="text-[14px] font-medium">{node.name}</span>
</div>
<ChevronDown className={`w-3.5 h-3.5 transition-transform duration-200 ${isOpen ? "rotate-180" : ""}`} />
</button>
<div className={`overflow-hidden transition-all duration-300 ease-in-out ${
isOpen ? "max-h-40 opacity-100 mt-1" : "max-h-0 opacity-0"
}`}>
<div className="ml-5 pl-4 border-l border-neutral-200 dark:border-neutral-800 space-y-1 py-1">
{node.items.map(subItem => (
<button
key={subItem}
onClick={() => setActiveItem(subItem)}
className={`w-full flex items-center px-3 py-1.5 text-[13px] rounded-md transition-colors ${
activeItem === subItem
? "text-blue-600 dark:text-blue-400 font-medium"
: "text-neutral-500 hover:text-neutral-900 dark:text-neutral-500 dark:hover:text-neutral-300"
}`}
>
{subItem}
</button>
))}
</div>
</div>
</div>
)
}
})}
</div>
</div>
);
};
export default ExpandableNestedSidebar;
Elegant Collapsible Sidebar
import React, { useState } from "react";
import { LayoutDashboard, Users, Settings, ChevronRight, ChevronLeft, LogOut } from "lucide-react";
const CollapseSidebar = () => {
const [isCollapsed, setIsCollapsed] = useState(false);
const [activeItem, setActiveItem] = useState("Dashboard");
const menuItems = [
{ name: "Dashboard", icon: LayoutDashboard },
{ name: "Users", icon: Users },
{ name: "Settings", icon: Settings },
];
return (
<div
className={`flex flex-col bg-white dark:bg-[#0A0A0A] h-screen border-r border-neutral-200/60 dark:border-white/10 shadow-sm transition-all duration-300 ease-in-out ${
isCollapsed ? "w-[80px]" : "w-[260px]"
}`}
>
<div className="flex items-center justify-between p-6">
<div className={`flex items-center gap-3 overflow-hidden transition-all duration-300 ${isCollapsed ? "w-0 opacity-0" : "w-auto opacity-100"}`}>
<div className="w-8 h-8 bg-neutral-900 dark:bg-white rounded-lg min-w-[32px] flex items-center justify-center">
<span className="text-white dark:text-neutral-900 font-bold">F</span>
</div>
<span className="font-semibold text-[18px] text-neutral-900 dark:text-white whitespace-nowrap">
Fusion
</span>
</div>
<button
onClick={() => setIsCollapsed(!isCollapsed)}
className="p-1.5 rounded-lg border border-neutral-200 dark:border-neutral-800 text-neutral-500 hover:bg-neutral-100 dark:hover:bg-neutral-900 transition-colors shadow-sm ml-auto"
>
{isCollapsed ? <ChevronRight size={16} /> : <ChevronLeft size={16} />}
</button>
</div>
<div className="flex-1 overflow-y-auto px-4 py-4 space-y-2">
{menuItems.map((item) => {
const isActive = activeItem === item.name;
return (
<button
key={item.name}
onClick={() => setActiveItem(item.name)}
className={`flex items-center rounded-xl transition-all duration-200 group relative ${
isActive
? "bg-neutral-100 dark:bg-neutral-900 text-neutral-900 dark:text-white"
: "text-neutral-500 hover:bg-neutral-50 dark:hover:bg-neutral-900/50 hover:text-neutral-800 dark:hover:text-neutral-300"
} ${isCollapsed ? "p-3 justify-center" : "px-4 py-3 w-full"}`}
title={isCollapsed ? item.name : undefined}
>
<item.icon className="w-5 h-5 min-w-[20px]" strokeWidth={isActive ? 2.5 : 2} />
<span className={`text-[14px] font-medium ml-3 whitespace-nowrap overflow-hidden transition-all duration-300 ${
isCollapsed ? "w-0 opacity-0 ml-0" : "w-auto opacity-100"
}`}>
{item.name}
</span>
</button>
)
})}
</div>
<div className="p-4 border-t border-neutral-200/60 dark:border-white/10">
<button className={`flex items-center justify-center p-3 rounded-xl hover:bg-red-50 dark:hover:bg-red-500/10 text-red-500 dark:text-red-400 transition-colors w-full ${isCollapsed ? "" : "gap-3"}`}>
<LogOut className="w-5 h-5 min-w-[20px]" />
<span className={`text-[14px] font-medium whitespace-nowrap overflow-hidden transition-all duration-300 ${
isCollapsed ? "w-0 opacity-0" : "w-auto opacity-100"
}`}>
Sign Out
</span>
</button>
</div>
</div>
);
};
export default CollapseSidebar;