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

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

Basic Example

A simple sidebar with icon navigation

Main Content Area

The sidebar is fixed to the left. Try clicking the navigation items!

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

Nested Menus

Unlimited depth with collapsible submenus

Multi-Level Navigation

Click on items with arrows to expand/collapse submenus. The component supports unlimited nesting depth.

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

Navigation with Badges

Add badges to show counts or status

Notification Badges

Badges can display counts, status, or notifications.

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

Light Theme Variant

Switch between light and dark themes

Light Sidebar Theme

The sidebar component adapts to light or dark theme variants. Use variant: 'theme' to follow the active theme instead.

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

State Persistence

Remember expanded menus across page reloads

Persistent State

Expand some menus, then reload the page. The expanded state will be remembered!

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

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'
        }
    }
});