Sidebar Component
JSON-configurable navigation sidebar with unlimited depth nesting, mobile toggle, and theme variants. Perfect for admin panels, documentation sites, and applications with complex navigation.
Features
Unlimited Nesting
Recursive submenu rendering supports infinite depth with proper indentation and animations.
Mobile Responsive
Slide-out drawer with overlay on mobile devices. Configurable breakpoint.
State Persistence
Remember expanded submenus using localStorage for seamless user experience.
Flexible Positioning
Fixed or static positioning, left or right alignment, custom width and top offset.
<div class="feature-grid">
<div class="card">
<div class="card-body">
<div class="mb-3 text-primary" data-icon="layers" data-size="32"></div>
<h3 class="card-title">Unlimited Nesting</h3>
<p class="card-text">Recursive submenu rendering supports infinite depth with proper indentation and animations.</p>
</div>
</div>
<div class="card">
<div class="card-body">
<div class="mb-3 text-success" data-icon="smartphone" data-size="32"></div>
<h3 class="card-title">Mobile Responsive</h3>
<p class="card-text">Slide-out drawer with overlay on mobile devices. Configurable breakpoint.</p>
</div>
</div>
<div class="card">
<div class="card-body">
<div class="mb-3 text-info" data-icon="save" data-size="32"></div>
<h3 class="card-title">State Persistence</h3>
<p class="card-text">Remember expanded submenus using localStorage for seamless user experience.</p>
</div>
</div>
<div class="card">
<div class="card-body">
<div class="mb-3 text-warning" data-icon="layout" data-size="32"></div>
<h3 class="card-title">Flexible Positioning</h3>
<p class="card-text">Fixed or static positioning, left or right alignment, custom width and top offset.</p>
</div>
</div>
</div>Add a sidebar to your page in three simple steps
Step 1: Add HTML Container
Add an <aside> element to your page where you want the sidebar to appear:
<aside id="my-sidebar"></aside>
<main class="content">
<!-- Your page content -->
</main>
Step 2: Include Domma
Add Domma CSS and JavaScript to your page:
<!-- CSS -->
<link rel="stylesheet" href="dist/domma.css">
<link rel="stylesheet" href="dist/elements.css">
<!-- JavaScript -->
<script src="dist/domma.min.js"></script>
Step 3: Initialize the Sidebar
Call Domma.elements.sidebar() with your navigation items:
Domma.elements.sidebar('#my-sidebar', {
items: [
{ text: 'Home', url: '/', icon: 'home' },
{ text: 'About', url: '/about', icon: 'info' },
{ text: 'Contact', url: '/contact', icon: 'mail' }
]
});
Note: The sidebar component will automatically generate all HTML structure, styling, and interactivity. You only need to provide the empty container element and configuration options.
Basic Example
A simple sidebar with icon navigation
JavaScript
const sidebar = Domma.elements.sidebar('#sidebar-basic', {
contentSelector: '#demo-content-basic',
position: 'left',
fixed: true,
width: '250px',
top: '60px',
header: {
title: 'Navigation',
toggle: true
},
items: [
{ text: 'Dashboard', url: '#dashboard', icon: 'layout', section: 'dashboard' },
{ text: 'Users', url: '#users', icon: 'users', section: 'users' },
{ text: 'Settings', url: '#settings', icon: 'settings', section: 'settings' }
],
variant: 'dark',
activeSection: 'dashboard'
});
<p class="mb-6 text-gray-600">A simple sidebar with icon navigation</p>
<div class="demo-container mb-6">
<aside id="sidebar-basic"></aside>
<div class="demo-content with-sidebar" id="demo-content-basic">
<h3>Main Content Area</h3>
<p>The sidebar is fixed to the left. Try clicking the navigation items!</p>
<button type="button" id="toggle-basic" class="btn btn-primary mt-4">Toggle Sidebar (Mobile)</button>
</div>
</div>
<h3 class="text-xl font-semibold mb-3">JavaScript</h3>
<div class="code-block language-javascript">
<pre><code>
const sidebar = Domma.elements.sidebar('#sidebar-basic', {
contentSelector: '#demo-content-basic',
position: 'left',
fixed: true,
width: '250px',
top: '60px',
header: {
title: 'Navigation',
toggle: true
},
items: [
{ text: 'Dashboard', url: '#dashboard', icon: 'layout', section: 'dashboard' },
{ text: 'Users', url: '#users', icon: 'users', section: 'users' },
{ text: 'Settings', url: '#settings', icon: 'settings', section: 'settings' }
],
variant: 'dark',
activeSection: 'dashboard'
});
</code></pre>
</div>/**
* Basic Example - from public/showcase/sidebar.
*/
export function mount(root) {
const sidebarBasic = E.sidebar(root.querySelector('#sidebar-basic'), {
contentSelector: '#demo-content-basic',
position: 'left',
fixed: true,
width: '250px',
top: '60px',
header: {
title: 'Navigation',
toggle: true
},
items: [
{ text: 'Dashboard', url: '#dashboard', icon: 'layout', section: 'dashboard' },
{ text: 'Users', url: '#users', icon: 'users', section: 'users' },
{ text: 'Reports', url: '#reports', icon: 'chart-bar', section: 'reports' },
{ text: 'Settings', url: '#settings', icon: 'settings', section: 'settings' }
],
variant: 'dark',
activeSection: 'dashboard',
push: true, // Push content instead of overlay
contentSelector: '.demo-content' // Element to push
});
$(root).find('#toggle-basic').on('click', () => sidebarBasic.toggle());
}Nested Menus
Unlimited depth with collapsible submenus
JavaScript
const sidebar = Domma.elements.sidebar('#sidebar-nested', {
contentSelector: '#demo-content-nested',
items: [
{ text: 'Dashboard', url: '#', icon: 'layout' },
{
text: 'Products',
icon: 'box',
items: [
{ text: 'All Products', url: '#products' },
{ text: 'Categories', url: '#categories' },
{
text: 'Advanced',
items: [
{ text: 'Import', url: '#import' },
{ text: 'Export', url: '#export' }
]
}
]
},
{ divider: true },
{ heading: 'SYSTEM' },
{ text: 'Settings', url: '#settings', icon: 'settings' }
]
});
<p class="mb-6 text-gray-600">Unlimited depth with collapsible submenus</p>
<div class="demo-container mb-6">
<aside id="sidebar-nested"></aside>
<div class="demo-content with-sidebar" id="demo-content-nested">
<h3>Multi-Level Navigation</h3>
<p>Click on items with arrows to expand/collapse submenus. The component supports unlimited nesting depth.</p>
<button type="button" id="expand-all" class="btn btn-primary mt-4 mr-2">Expand All</button>
<button type="button" id="collapse-all" class="btn btn-secondary mt-4">Collapse All</button>
</div>
</div>
<h3 class="text-xl font-semibold mb-3">JavaScript</h3>
<div class="code-block language-javascript">
<pre><code>
const sidebar = Domma.elements.sidebar('#sidebar-nested', {
contentSelector: '#demo-content-nested',
items: [
{ text: 'Dashboard', url: '#', icon: 'layout' },
{
text: 'Products',
icon: 'box',
items: [
{ text: 'All Products', url: '#products' },
{ text: 'Categories', url: '#categories' },
{
text: 'Advanced',
items: [
{ text: 'Import', url: '#import' },
{ text: 'Export', url: '#export' }
]
}
]
},
{ divider: true },
{ heading: 'SYSTEM' },
{ text: 'Settings', url: '#settings', icon: 'settings' }
]
});
</code></pre>
</div>/**
* Nested Menus - from public/showcase/sidebar.
*/
export function mount(root) {
// Nested Example
const sidebarNested = E.sidebar(root.querySelector('#sidebar-nested'), {
contentSelector: '#demo-content-nested',
position: 'left',
fixed: true,
width: '250px',
top: '60px',
header: { title: 'Multi-Level Menu' },
items: [
{ text: 'Dashboard', url: '#', icon: 'layout' },
{
text: 'Products',
icon: 'box',
items: [
{ text: 'All Products', url: '#products' },
{ text: 'Categories', url: '#categories' },
{
text: 'Advanced',
items: [
{ text: 'Import', url: '#import' },
{ text: 'Export', url: '#export' },
{
text: 'Tools',
items: [
{ text: 'Bulk Edit', url: '#bulk-edit' },
{ text: 'Price Update', url: '#price-update' }
]
}
]
}
]
},
{
text: 'Orders',
icon: 'cart',
items: [
{ text: 'All Orders', url: '#orders' },
{ text: 'Pending', url: '#pending' },
{ text: 'Completed', url: '#completed' }
]
},
{ divider: true },
{ heading: 'SYSTEM' },
{ text: 'Settings', url: '#settings', icon: 'settings' },
{ text: 'Help', url: '#help', icon: 'help-circle' }
],
variant: 'dark'
});
$(root).find('#expand-all').on('click', () => sidebarNested.expandAll());
$(root).find('#collapse-all').on('click', () => sidebarNested.collapseAll());
}Navigation with Badges
Add badges to show counts or status
JavaScript
Domma.elements.sidebar('#sidebar-badges', {
contentSelector: '#demo-content-badges',
items: [
{ text: 'Inbox', url: '#inbox', icon: 'mail', badge: '12' },
{ text: 'Notifications', url: '#notifications', icon: 'bell', badge: '3' },
{ text: 'Messages', url: '#messages', icon: 'message-square', badge: '99+' }
]
});
<p class="mb-6 text-gray-600">Add badges to show counts or status</p>
<div class="demo-container mb-6">
<aside id="sidebar-badges"></aside>
<div class="demo-content with-sidebar" id="demo-content-badges">
<h3>Notification Badges</h3>
<p>Badges can display counts, status, or notifications.</p>
</div>
</div>
<h3 class="text-xl font-semibold mb-3">JavaScript</h3>
<div class="code-block language-javascript">
<pre><code>
Domma.elements.sidebar('#sidebar-badges', {
contentSelector: '#demo-content-badges',
items: [
{ text: 'Inbox', url: '#inbox', icon: 'mail', badge: '12' },
{ text: 'Notifications', url: '#notifications', icon: 'bell', badge: '3' },
{ text: 'Messages', url: '#messages', icon: 'message-square', badge: '99+' }
]
});
</code></pre>
</div>/**
* Navigation with Badges - from public/showcase/sidebar.
*/
export function mount(root) {
// Badges Example
E.sidebar(root.querySelector('#sidebar-badges'), {
contentSelector: '#demo-content-badges',
position: 'left',
fixed: true,
width: '250px',
top: '60px',
header: { title: 'Notifications' },
items: [
{ text: 'Inbox', url: '#inbox', icon: 'mail', badge: '12' },
{ text: 'Notifications', url: '#notifications', icon: 'bell', badge: '3' },
{ text: 'Messages', url: '#messages', icon: 'message-square', badge: '99+' },
{ text: 'Tasks', url: '#tasks', icon: 'check-square', badge: '5' }
],
variant: 'dark'
});
}Light Theme Variant
Switch between light and dark themes
JavaScript
Domma.elements.sidebar('#sidebar-light', {
contentSelector: '#demo-content-light',
variant: 'light', // or 'dark', or 'theme' to follow the active theme
items: [/* ... */]
});
<p class="mb-6 text-gray-600">Switch between light and dark themes</p>
<div class="demo-container mb-6">
<aside id="sidebar-light"></aside>
<div class="demo-content with-sidebar" id="demo-content-light">
<h3>Light Sidebar Theme</h3>
<p>The sidebar component adapts to light or dark theme variants. Use <code>variant: 'theme'</code> to follow the active theme instead.</p>
</div>
</div>
<h3 class="text-xl font-semibold mb-3">JavaScript</h3>
<div class="code-block language-javascript">
<pre><code>
Domma.elements.sidebar('#sidebar-light', {
contentSelector: '#demo-content-light',
variant: 'light', // or 'dark', or 'theme' to follow the active theme
items: [/* ... */]
});
</code></pre>
</div>/**
* Light Theme Variant - from public/showcase/sidebar.
*/
export function mount(root) {
// Light Theme Example
E.sidebar(root.querySelector('#sidebar-light'), {
contentSelector: '#demo-content-light',
position: 'left',
fixed: true,
width: '250px',
top: '60px',
header: { title: 'Light Theme' },
items: [
{ text: 'Home', url: '#', icon: 'home' },
{ text: 'Profile', url: '#profile', icon: 'user' },
{ text: 'Settings', url: '#settings', icon: 'settings' }
],
variant: 'light'
});
}State Persistence
Remember expanded menus across page reloads
JavaScript
Domma.elements.sidebar('#sidebar-persist', {
contentSelector: '#demo-content-persist',
persistExpanded: true,
persistKey: 'my-app-sidebar', // Unique key for this sidebar
items: [/* ... */]
});
<p class="mb-6 text-gray-600">Remember expanded menus across page reloads</p>
<div class="demo-container mb-6">
<aside id="sidebar-persist"></aside>
<div class="demo-content with-sidebar" id="demo-content-persist">
<h3>Persistent State</h3>
<p>Expand some menus, then reload the page. The expanded state will be remembered!</p>
<button type="button" id="reload-demo" class="btn btn-primary mt-4">Reload Page</button>
</div>
</div>
<h3 class="text-xl font-semibold mb-3">JavaScript</h3>
<div class="code-block language-javascript">
<pre><code>
Domma.elements.sidebar('#sidebar-persist', {
contentSelector: '#demo-content-persist',
persistExpanded: true,
persistKey: 'my-app-sidebar', // Unique key for this sidebar
items: [/* ... */]
});
</code></pre>
</div>/**
* State Persistence - from public/showcase/sidebar.
*/
export function mount(root) {
// Persistence Example
E.sidebar(root.querySelector('#sidebar-persist'), {
contentSelector: '#demo-content-persist',
position: 'left',
fixed: true,
width: '250px',
top: '60px',
header: { title: 'Persistent State' },
items: [
{ text: 'Dashboard', url: '#', icon: 'layout' },
{
text: 'Menu 1',
icon: 'folder',
items: [
{ text: 'Item 1.1', url: '#' },
{ text: 'Item 1.2', url: '#' }
]
},
{
text: 'Menu 2',
icon: 'folder',
items: [
{ text: 'Item 2.1', url: '#' },
{ text: 'Item 2.2', url: '#' }
]
}
],
variant: 'dark',
persistExpanded: true,
persistKey: 'showcase-sidebar-persist'
});
$(root).find('#reload-demo').on('click', () => location.reload());
}API Reference
Options
| Option | Type | Default | Description |
|---|---|---|---|
position |
String | 'left' | 'left' or 'right' |
fixed |
Boolean | true | Fixed or static positioning |
width |
String | '250px' | Sidebar width |
top |
String | '0' | Top offset (e.g., '60px' for navbar) |
header |
Object | null | { title, toggle, icon } |
items |
Array | [] | Navigation items |
footer |
Object | null | { text, html } |
variant |
String | 'dark' | 'light', 'dark', or 'theme' (follows the active theme) |
collapsible |
Boolean | true | Mobile toggle behaviour |
collapseAt |
Number | 768 | Breakpoint (px) |
push |
Boolean | true | Push content instead of overlay when sidebar opens |
contentSelector |
String | '.main-content' | CSS selector for content element to push (when push: true) |
activeSection |
String | null | Current active section |
persistExpanded |
Boolean | false | Persist expanded state |
persistKey |
String | null | localStorage key |
Methods
| Method | Description |
|---|---|
open() |
Open sidebar (mobile) |
close() |
Close sidebar (mobile) |
toggle() |
Toggle sidebar (mobile) |
isOpen() |
Check if sidebar is open |
setActive(section) |
Set active section |
setItems(items) |
Replace all items |
addItem(item, index) |
Add item at index |
removeItem(index) |
Remove item at index |
expandAll() |
Expand all submenus |
collapseAll() |
Collapse all submenus |
<h3 class="text-xl font-semibold mb-3">Options</h3>
<div class="table-responsive mb-6">
<table class="table">
<thead>
<tr>
<th>Option</th>
<th>Type</th>
<th>Default</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>position</code></td>
<td>String</td>
<td>'left'</td>
<td>'left' or 'right'</td>
</tr>
<tr>
<td><code>fixed</code></td>
<td>Boolean</td>
<td>true</td>
<td>Fixed or static positioning</td>
</tr>
<tr>
<td><code>width</code></td>
<td>String</td>
<td>'250px'</td>
<td>Sidebar width</td>
</tr>
<tr>
<td><code>top</code></td>
<td>String</td>
<td>'0'</td>
<td>Top offset (e.g., '60px' for navbar)</td>
</tr>
<tr>
<td><code>header</code></td>
<td>Object</td>
<td>null</td>
<td>{ title, toggle, icon }</td>
</tr>
<tr>
<td><code>items</code></td>
<td>Array</td>
<td>[]</td>
<td>Navigation items</td>
</tr>
<tr>
<td><code>footer</code></td>
<td>Object</td>
<td>null</td>
<td>{ text, html }</td>
</tr>
<tr>
<td><code>variant</code></td>
<td>String</td>
<td>'dark'</td>
<td>'light', 'dark', or 'theme' (follows the active theme)</td>
</tr>
<tr>
<td><code>collapsible</code></td>
<td>Boolean</td>
<td>true</td>
<td>Mobile toggle behaviour</td>
</tr>
<tr>
<td><code>collapseAt</code></td>
<td>Number</td>
<td>768</td>
<td>Breakpoint (px)</td>
</tr>
<tr>
<td><code>push</code></td>
<td>Boolean</td>
<td>true</td>
<td>Push content instead of overlay when sidebar opens</td>
</tr>
<tr>
<td><code>contentSelector</code></td>
<td>String</td>
<td>'.main-content'</td>
<td>CSS selector for content element to push (when push: true)</td>
</tr>
<tr>
<td><code>activeSection</code></td>
<td>String</td>
<td>null</td>
<td>Current active section</td>
</tr>
<tr>
<td><code>persistExpanded</code></td>
<td>Boolean</td>
<td>false</td>
<td>Persist expanded state</td>
</tr>
<tr>
<td><code>persistKey</code></td>
<td>String</td>
<td>null</td>
<td>localStorage key</td>
</tr>
</tbody>
</table>
</div>
<h3 class="text-xl font-semibold mb-3">Methods</h3>
<div class="table-responsive">
<table class="table">
<thead>
<tr>
<th>Method</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>open()</code></td>
<td>Open sidebar (mobile)</td>
</tr>
<tr>
<td><code>close()</code></td>
<td>Close sidebar (mobile)</td>
</tr>
<tr>
<td><code>toggle()</code></td>
<td>Toggle sidebar (mobile)</td>
</tr>
<tr>
<td><code>isOpen()</code></td>
<td>Check if sidebar is open</td>
</tr>
<tr>
<td><code>setActive(section)</code></td>
<td>Set active section</td>
</tr>
<tr>
<td><code>setItems(items)</code></td>
<td>Replace all items</td>
</tr>
<tr>
<td><code>addItem(item, index)</code></td>
<td>Add item at index</td>
</tr>
<tr>
<td><code>removeItem(index)</code></td>
<td>Remove item at index</td>
</tr>
<tr>
<td><code>expandAll()</code></td>
<td>Expand all submenus</td>
</tr>
<tr>
<td><code>collapseAll()</code></td>
<td>Collapse all submenus</td>
</tr>
</tbody>
</table>
</div>Use $.setup() for declarative initialization
$.setup({
'#my-sidebar': {
component: 'sidebar',
options: {
variant: 'dark',
items: [
{ text: 'Home', url: '/', icon: 'home' },
{ text: 'About', url: '/about', icon: 'info' }
],
activeSection: 'home'
}
}
});