@excel-pros/sidebar-library
v1.0.0
Published
Dynamic sidebar library for React + TailwindCSS
Readme
React Dynamic Sidebar
A highly customizable, responsive sidebar component for React applications with dynamic routing, collapsible navigation, and mobile-first design.
Features
- 🎨 Fully Customizable - Complete control over styling and theming (no built-in themes)
- 📱 Mobile Responsive - Touch gestures, swipe support, and adaptive layouts
- 🎯 Dynamic Routing - Works with React Router or vanilla React routing
- 🔧 Flexible Structure - Support for nested menus, groups, and custom components
- 🎛️ Context API - Global sidebar state management
- 📦 Zero Dependencies - Only requires React and Lucide React for icons
- 🔄 Browser History - Seamless integration with browser back/forward buttons
- 👆 Touch Friendly - Optimized for mobile with swipe gestures and touch interactions
- ⚡ Smooth Animations - Configurable transitions and micro-interactions
- 🎨 CSS-in-JS Ready - Works with any styling solution (Tailwind, Styled Components, CSS Modules, etc.)
Installation
npm install @excelpros/sidebar-library
# or
yarn add @excelpros/sidebar-libraryPeer Dependencies
For React Router integration:
npm install react-router-dom
# or
yarn add react-router-domQuick Start
Basic Implementation (Vanilla React)
import React, { useState, useEffect } from 'react';
import {
Sidebar,
SidebarLayout,
DynamicSidebarMenu,
SidebarFooter
} from 'react-dynamic-sidebar';
import { Home, Settings, User, Menu, ChevronLeft } from 'lucide-react';
function App() {
const [currentPath, setCurrentPath] = useState(window.location.pathname);
const handleNavigate = (path) => {
setCurrentPath(path);
window.history.pushState({}, "", path);
};
// Handle browser back/forward
useEffect(() => {
const onPopState = () => setCurrentPath(window.location.pathname);
window.addEventListener("popstate", onPopState);
return () => window.removeEventListener("popstate", onPopState);
}, []);
// Define your navigation structure (user-defined)
const menuItems = [
{
type: "group",
label: "Main",
items: [
{
label: "Home",
icon: Home,
path: "/",
className: "px-3 py-2 rounded-md hover:bg-blue-100",
},
{
label: "Settings",
icon: Settings,
className: "px-3 py-2 rounded-md hover:bg-gray-100",
children: [
{
label: "Profile",
icon: User,
path: "/settings/profile",
className: "px-3 py-2 rounded-md hover:bg-green-100",
}
]
}
]
}
];
// Component mapping for routing (user-defined)
const componentMap = {
"/": () => <div className="p-6">🏠 Home Page</div>,
"/settings/profile": () => <div className="p-6">👤 Profile Settings</div>,
};
const userData = {
name: "John Doe",
role: "Admin",
avatar: "/avatar.jpg"
};
const ActiveComponent = componentMap[currentPath] ||
(() => <div>Page not found</div>);
return (
<SidebarLayout
navbar={<div className="bg-gray-100 p-4 border-b">Navigation Bar</div>}
sidebar={
<Sidebar
title="My Company"
logo="/logo.png"
menuIcon={Menu}
closeIcon={ChevronLeft}
sidebarColor="bg-white"
footer={
<SidebarFooter
user={userData}
onLogout={() => alert("Logged out!")}
/>
}
>
<DynamicSidebarMenu
items={menuItems}
currentPath={currentPath}
onNavigate={handleNavigate}
/>
</Sidebar>
}
>
<ActiveComponent onNavigate={handleNavigate} />
</SidebarLayout>
);
}React Router Integration
For applications using React Router, the integration is even simpler:
import { SidebarLayout, Sidebar, DynamicSidebarMenu } from "react-dynamic-sidebar";
import { Routes, Route, useNavigate, useLocation } from "react-router-dom";
import { Menu, ChevronLeft, Home, Settings, User } from "lucide-react";
function App() {
const navigate = useNavigate();
const location = useLocation();
const handleNavigate = (path) => {
navigate(path); // React Router handles the navigation
};
// Define your navigation structure (user customizable)
const menuItems = [
{
type: "group",
label: "Overview",
items: [
{
label: "Home",
icon: Home,
path: "/",
className: "px-3 py-2 rounded-md hover:bg-blue-100",
},
{
label: "Dashboard",
icon: Settings,
path: "/dashboard",
className: "px-3 py-2 rounded-md hover:bg-green-100",
}
]
},
{
type: "group",
label: "Settings",
items: [
{
label: "Settings",
icon: Settings,
className: "px-3 py-2 rounded-md hover:bg-gray-100",
children: [
{
label: "Profile",
icon: User,
path: "/settings/profile",
className: "px-3 py-2 rounded-md hover:bg-purple-100",
},
{
label: "Security",
icon: User,
path: "/settings/security",
className: "px-3 py-2 rounded-md hover:bg-red-100",
}
]
}
]
}
];
// Page components (user-defined)
const Home = () => <div className="p-6 text-xl">🏠 Home Page</div>;
const Profile = () => <div className="p-6 text-xl">👤 Profile Settings</div>;
const Security = () => <div className="p-6 text-xl">🔒 Security Settings</div>;
// Map paths to components for route generation
const routeComponentMap = {
"/": Home,
"/dashboard": () => <div className="p-6 text-xl">📊 Dashboard</div>,
"/settings/profile": Profile,
"/settings/security": Security,
};
return (
<SidebarLayout
navbar={<div className="bg-gray-100 p-4 border-b">Top Navigation</div>}
sidebar={
<Sidebar
title="My Company"
logo="/logo.png"
menuIcon={Menu}
closeIcon={ChevronLeft}
>
<DynamicSidebarMenu
items={menuItems}
currentPath={location.pathname}
onNavigate={handleNavigate}
/>
</Sidebar>
}
>
<Routes>
{Object.entries(routeComponentMap).map(([path, Component]) => (
<Route key={path} path={path} element={<Component />} />
))}
<Route path="*" element={<div className="p-6">404 - Not Found</div>} />
</Routes>
</SidebarLayout>
);
}Components
Sidebar
The main sidebar container with extensive customization options.
<Sidebar
// Layout
width="220px"
collapsedWidth="60px"
mobileWidth="200px"
initialCollapsed={false}
// Branding
title="My Application"
logo="/logo.png"
// Navigation
currentPath="/dashboard"
onNavigate={(path) => console.log('Navigate to:', path)}
// Mobile settings
mobileSettings={{
swipeToClose: true,
backdropClick: true,
autoClose: false,
slideDirection: "left"
}}
// Styling
sidebarColor="bg-white"
animations={{
enabled: true,
duration: 300,
sidebar: { width: true, transform: true }
}}
>
{/* Sidebar content */}
</Sidebar>DynamicSidebarMenu
Renders navigation items from a configuration object.
const menuItems = [
{
type: "group",
label: "Navigation",
items: [
{
label: "Dashboard",
icon: Home,
path: "/dashboard"
},
{
label: "Settings",
icon: Settings,
children: [
{
label: "Profile",
icon: User,
path: "/settings/profile"
}
]
}
]
}
];
<DynamicSidebarMenu
items={menuItems}
currentPath={currentPath}
onNavigate={handleNavigate}
/>SidebarMenuItem
Individual menu item component for custom implementations.
<SidebarMenuItem
icon={Home}
label="Dashboard"
href="/dashboard"
currentPath={currentPath}
onNavigate={handleNavigate}
className="custom-menu-item"
/>SidebarLayout
Layout wrapper that manages sidebar and main content positioning.
<SidebarLayout
sidebar={<Sidebar>...</Sidebar>}
navbar={<Navbar />} // Optional
>
<main>Your main content</main>
</SidebarLayout>SidebarFooter
Customizable footer component for user info and actions.
<SidebarFooter
user={{
name: "John Doe",
role: "Admin",
avatar: "/avatar.jpg"
}}
onLogout={() => console.log('Logout')}
/>Styling & Themes
The sidebar components are fully customizable with your own CSS classes and styling:
<SidebarMenuItem
icon={Home}
label="Dashboard"
path="/dashboard"
// Custom styling (user-defined)
className="px-4 py-3 rounded-lg hover:bg-blue-50 transition-colors"
iconClassName="text-blue-600 group-hover:text-blue-700"
collapsedClassName="p-3 rounded-full hover:bg-gray-100"
childrenClassName="ml-6 border-l-2 border-gray-200"
/>Menu Item Structure
Each menu item can be customized with your preferred styling:
const menuItems = [
{
type: "group",
label: "Navigation",
className: "mb-4", // Custom group styling
items: [
{
label: "Dashboard",
icon: Home,
path: "/dashboard",
// Apply your own styles
className: "px-4 py-2 rounded-md hover:bg-indigo-100 text-gray-700",
iconClassName: "text-indigo-500",
collapsedClassName: "p-2 rounded-full hover:bg-indigo-50"
},
{
label: "Settings",
icon: Settings,
className: "px-4 py-2 rounded-md hover:bg-gray-100",
children: [
{
label: "Profile",
icon: User,
path: "/profile",
className: "px-3 py-2 ml-4 rounded hover:bg-green-50 text-sm",
iconClassName: "text-green-600"
}
]
}
]
}
];Sidebar Styling
Customize the main sidebar appearance:
<Sidebar
// Background and colors
sidebarColor="bg-gradient-to-b from-blue-900 to-blue-800"
sidebarBorderColor="#1e40af"
// Logo and branding
title="My App"
logo="/logo.png"
logoSize={{
mobile: { expanded: 40, collapsed: 28 },
desktop: { expanded: 60, collapsed: 40 }
}}
// Custom styling
className="shadow-2xl"
>
{/* Your menu items */}
</Sidebar>Mobile Features
The sidebar includes comprehensive mobile support:
- Touch Gestures: Swipe to open/close
- Backdrop Dismiss: Tap outside to close
- Responsive Breakpoints: Automatic mobile/tablet detection
- Slide Directions: Left, right, top, bottom slide animations
<Sidebar
mobileSettings={{
swipeToClose: true,
backdropClick: true,
autoClose: true, // Auto-close after navigation
slideDirection: "left",
overlayOpacity: 0.4,
swipeThreshold: 50
}}
breakpoints={{
mobile: 768,
tablet: 1024
}}
/>Animation Configuration
Highly customizable animation system:
<Sidebar
animations={{
enabled: true,
duration: 300,
easing: "ease-in-out",
sidebar: {
width: true,
transform: true,
opacity: false
},
icons: {
rotation: true,
scale: true,
opacity: true
},
menuItems: {
stagger: true,
slideIn: true,
delay: 50
},
effects: {
glow: false,
shake: false,
pulse: false
}
}}
/>Context API
Use the sidebar context for global state management:
import { SidebarProvider, useSidebar } from 'react-dynamic-sidebar';
function App() {
return (
<SidebarProvider initialCollapsed={false}>
<MyComponent />
</SidebarProvider>
);
}
function MyComponent() {
const { collapsed, toggle } = useSidebar();
return (
<button onClick={toggle}>
{collapsed ? 'Expand' : 'Collapse'} Sidebar
</button>
);
}Advanced Usage
Routing Integration
Vanilla React (Manual Routing)
For applications without React Router, use manual route handling:
import React, { useState, useEffect } from 'react';
function App() {
const [currentPath, setCurrentPath] = useState(window.location.pathname);
const handleNavigate = (path) => {
setCurrentPath(path);
window.history.pushState({}, "", path);
};
// Handle browser back/forward
useEffect(() => {
const onPopState = () => setCurrentPath(window.location.pathname);
window.addEventListener("popstate", onPopState);
return () => window.removeEventListener("popstate", onPopState);
}, []);
const componentMap = {
"/": HomePage,
"/settings": SettingsPage,
};
const ActiveComponent = componentMap[currentPath] || NotFoundPage;
return (
<SidebarLayout sidebar={sidebar}>
<ActiveComponent />
</SidebarLayout>
);
}React Router Integration
The sidebar works seamlessly with React Router:
import { useNavigate, useLocation, Routes, Route } from 'react-router-dom';
function App() {
const navigate = useNavigate();
const location = useLocation();
const handleNavigate = (path) => {
navigate(path); // React Router handles everything
};
return (
<SidebarLayout
sidebar={
<Sidebar>
<DynamicSidebarMenu
items={menuItems}
currentPath={location.pathname}
onNavigate={handleNavigate}
/>
</Sidebar>
}
>
<Routes>
<Route path="/" element={<HomePage />} />
<Route path="/settings/*" element={<SettingsPage />} />
<Route path="*" element={<NotFoundPage />} />
</Routes>
</SidebarLayout>
);
}Dynamic Route Generation
For cleaner code, generate routes dynamically:
const routeComponentMap = {
"/": HomePage,
"/dashboard": DashboardPage,
"/settings/profile": ProfilePage,
"/settings/security": SecurityPage,
};
// Generate routes automatically
<Routes>
{Object.entries(routeComponentMap).map(([path, Component]) => (
<Route key={path} path={path} element={<Component />} />
))}
<Route path="*" element={<div>404 - Not Found</div>} />
</Routes>Browser History Integration
The sidebar automatically integrates with browser history:
// Browser back/forward support
useEffect(() => {
const onPopState = () => setCurrentPath(window.location.pathname);
window.addEventListener("popstate", onPopState);
return () => window.removeEventListener("popstate", onPopState);
}, []);
const handleNavigate = (path) => {
setCurrentPath(path);
window.history.pushState({}, "", path); // Updates browser URL
};Custom Page Components
Define your page components and map them to routes:
// pages/Home.js
export default function Home({ onNavigate }) {
return (
<div className="p-6">
<h1>Welcome to Dashboard</h1>
<button onClick={() => onNavigate('/settings/profile')}>
Go to Profile
</button>
</div>
);
}
// componentMap.js
import Home from './pages/Home';
import Profile from './pages/Profile';
import Security from './pages/Security';
export const componentMap = {
"/": Home,
"/home": Home,
"/settings/profile": Profile,
"/settings/security": Security,
};Props Reference
Sidebar Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| initialCollapsed | boolean | false | Initial collapsed state |
| width | string | "220px" | Desktop sidebar width |
| collapsedWidth | string | "60px" | Desktop collapsed width |
| mobileWidth | string | "200px" | Mobile sidebar width
|mobileCollapsedWidth|string|-|Mobile sidebar widht collapsed|
| title | string | - | Sidebar title |
| logo | string | - | Logo image path |
| currentPath | string | - | Current active path |
| onNavigate | function | - | Navigation callback |
| mobileSettings | object | - | Mobile behavior configuration |
| animations | object | - | Animation configuration |
| sidebarColor | string | "bg-white" | Background color/class |
Menu Item Structure
Users define their own menu structure and styling:
interface MenuItem {
// Basic properties
type?: 'group';
label: string;
icon?: ComponentType;
path?: string;
children?: MenuItem[];
items?: MenuItem[]; // For groups
// Custom styling (user-defined)
className?: string; // Main item styling
iconClassName?: string; // Icon-specific styling
collapsedClassName?: string; // Styling when sidebar is collapsed
childrenClassName?: string; // Styling for nested items
}Example implementation:
const menuItems = [
{
type: "group",
label: "Main",
className: "mb-4 pb-2 border-b border-gray-200", // User's group styling
items: [
{
label: "Dashboard",
icon: Home,
path: "/dashboard",
// User defines their own styling
className: "flex items-center px-4 py-2 rounded-lg hover:bg-blue-50 text-gray-700 transition-colors duration-200",
iconClassName: "mr-3 text-blue-500 group-hover:text-blue-600",
collapsedClassName: "p-3 rounded-full hover:bg-blue-100 group"
}
]
}
];Browser Support
- Chrome/Edge 88+
- Firefox 85+
- Safari 14+
- Mobile browsers with touch support
Contributing
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
License
MIT License - see the LICENSE file for details.
Changelog
v1.0.0
- Initial release
- Core sidebar functionality
- Mobile responsiveness
- Animation system
- Theme presets
- Context API integration
