Skip to main content
Glama
sidebar-usage.md13.9 kB
# Sidebar Component Usage ## Overview The sidebar component provides a composable, themeable, and customizable navigation sidebar. It supports collapsible menus, mobile-responsive behavior, and multiple positioning options. The sidebar uses JavaScript for toggle functionality and smooth transitions. ## JavaScript Requirements ### Required Scripts ```html <!-- Include Basecoat CSS and JavaScript --> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/basecoat-css@latest/dist/basecoat.cdn.min.css"> <script src="https://cdn.jsdelivr.net/npm/basecoat-css@latest/dist/js/basecoat.min.js" defer></script> <script src="https://cdn.jsdelivr.net/npm/basecoat-css@latest/dist/js/sidebar.min.js" defer></script> ``` ## HTML Structure ### Basic Sidebar ```html <aside class="sidebar" aria-hidden="false"> <nav aria-label="Sidebar navigation"> <header> <a href="/" class="flex items-center gap-2 font-semibold"> <svg class="size-6"><!-- logo icon --></svg> <span>My App</span> </a> </header> <section class="scrollbar"> <div role="group" aria-labelledby="nav-main"> <span role="heading" id="nav-main">Main</span> <ul> <li> <a href="/dashboard" class="active"> <svg class="size-4"><!-- dashboard icon --></svg> Dashboard </a> </li> <li> <a href="/projects"> <svg class="size-4"><!-- folder icon --></svg> Projects </a> </li> <li> <a href="/settings"> <svg class="size-4"><!-- settings icon --></svg> Settings </a> </li> </ul> </div> </section> <footer> <div class="flex items-center gap-2"> <img src="/avatar.png" alt="User" class="size-8 rounded-full"> <span>John Doe</span> </div> </footer> </nav> </aside> <main> <button type="button" onclick="document.dispatchEvent(new CustomEvent('basecoat:sidebar'))"> Toggle Sidebar </button> <h1>Main Content</h1> </main> ``` ### Sidebar with Collapsible Sections ```html <aside class="sidebar" aria-hidden="false"> <nav aria-label="Main navigation"> <section class="scrollbar"> <div role="group" aria-labelledby="getting-started"> <span role="heading" id="getting-started">Getting Started</span> <ul> <li> <a href="/playground"> <svg class="size-4"><!-- terminal icon --></svg> Playground </a> </li> <li> <a href="/models"> <svg class="size-4"><!-- bot icon --></svg> Models </a> </li> <li> <details> <summary> <svg class="size-4"><!-- settings icon --></svg> Settings </summary> <ul> <li><a href="/settings/general">General</a></li> <li><a href="/settings/team">Team</a></li> <li><a href="/settings/billing">Billing</a></li> <li><a href="/settings/limits">Limits</a></li> </ul> </details> </li> </ul> </div> </section> </nav> </aside> ``` ## Component Elements ### Sidebar Container ```html <aside class="sidebar" aria-hidden="false" data-side="left"> ``` - `aria-hidden`: Controls visibility state (`true`/`false`) - `data-side`: Position (`left` or `right`, defaults to `left`) ### Navigation Structure ```html <nav aria-label="Sidebar navigation"> <header><!-- Logo, app name --></header> <section class="scrollbar"><!-- Navigation groups --></section> <footer><!-- User info, secondary actions --></footer> </nav> ``` ### Navigation Groups ```html <div role="group" aria-labelledby="group-id"> <span role="heading" id="group-id">Group Label</span> <ul> <li><a href="#">Link</a></li> <li><button>Action</button></li> </ul> </div> ``` ### Collapsible Submenu ```html <li> <details> <summary> <svg class="size-4"><!-- icon --></svg> Menu with Submenu </summary> <ul> <li><a href="#">Submenu Item 1</a></li> <li><a href="#">Submenu Item 2</a></li> </ul> </details> </li> ``` ## Implementation Examples ### Dashboard Sidebar ```html <aside class="sidebar" aria-hidden="false"> <nav aria-label="Dashboard navigation"> <header> <a href="/" class="flex items-center gap-2 font-semibold"> <svg class="size-6" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> <rect width="7" height="9" x="3" y="3" rx="1"></rect> <rect width="7" height="5" x="14" y="3" rx="1"></rect> <rect width="7" height="9" x="14" y="12" rx="1"></rect> <rect width="7" height="5" x="3" y="16" rx="1"></rect> </svg> <span>Dashboard</span> </a> </header> <section class="scrollbar"> <div role="group"> <ul> <li> <a href="/dashboard" class="active"> <svg class="size-4"><!-- home icon --></svg> Overview </a> </li> <li> <a href="/analytics"> <svg class="size-4"><!-- chart icon --></svg> Analytics </a> </li> <li> <a href="/customers"> <svg class="size-4"><!-- users icon --></svg> Customers </a> </li> <li> <a href="/products"> <svg class="size-4"><!-- package icon --></svg> Products </a> </li> </ul> </div> <hr class="my-4"> <div role="group" aria-labelledby="settings-group"> <span role="heading" id="settings-group">Settings</span> <ul> <li> <a href="/settings/profile"> <svg class="size-4"><!-- user icon --></svg> Profile </a> </li> <li> <a href="/settings/billing"> <svg class="size-4"><!-- credit-card icon --></svg> Billing </a> </li> <li> <a href="/settings/notifications"> <svg class="size-4"><!-- bell icon --></svg> Notifications </a> </li> </ul> </div> </section> <footer> <a href="/settings" class="flex items-center gap-3 p-2 rounded-lg hover:bg-accent"> <img src="/avatar.png" alt="" class="size-8 rounded-full"> <div class="flex-1 min-w-0"> <p class="text-sm font-medium truncate">John Doe</p> <p class="text-xs text-muted-foreground truncate">john@example.com</p> </div> <svg class="size-4 text-muted-foreground"><!-- chevron-right icon --></svg> </a> </footer> </nav> </aside> <main> <header class="flex items-center gap-4 p-4 border-b lg:hidden"> <button type="button" class="btn-icon-ghost" onclick="document.dispatchEvent(new CustomEvent('basecoat:sidebar'))"> <svg class="size-5"><!-- menu icon --></svg> </button> <h1 class="text-lg font-semibold">Dashboard</h1> </header> <!-- Main content --> </main> ``` ### Documentation Sidebar ```html <aside class="sidebar" aria-hidden="false"> <nav aria-label="Documentation navigation"> <header> <a href="/" class="flex items-center gap-2"> <span class="font-bold text-lg">Docs</span> </a> <div class="relative mt-4"> <input type="search" placeholder="Search..." class="input pl-9 w-full"> <svg class="absolute left-3 top-1/2 -translate-y-1/2 size-4 text-muted-foreground"><!-- search icon --></svg> </div> </header> <section class="scrollbar"> <div role="group" aria-labelledby="intro"> <span role="heading" id="intro">Introduction</span> <ul> <li><a href="/docs/getting-started">Getting Started</a></li> <li><a href="/docs/installation">Installation</a></li> <li><a href="/docs/theming">Theming</a></li> </ul> </div> <div role="group" aria-labelledby="components"> <span role="heading" id="components">Components</span> <ul> <li><a href="/docs/button">Button</a></li> <li><a href="/docs/input">Input</a></li> <li><a href="/docs/select">Select</a></li> <li><a href="/docs/dialog">Dialog</a></li> <li><a href="/docs/toast">Toast</a></li> </ul> </div> <div role="group" aria-labelledby="guides"> <span role="heading" id="guides">Guides</span> <ul> <li><a href="/docs/forms">Building Forms</a></li> <li><a href="/docs/layouts">Layouts</a></li> <li><a href="/docs/accessibility">Accessibility</a></li> </ul> </div> </section> </nav> </aside> ``` ## JavaScript Events ### Toggle Sidebar ```javascript // Toggle sidebar (default behavior) document.dispatchEvent(new CustomEvent('basecoat:sidebar')); // Open sidebar document.dispatchEvent(new CustomEvent('basecoat:sidebar', { detail: { action: 'open' } })); // Close sidebar document.dispatchEvent(new CustomEvent('basecoat:sidebar', { detail: { action: 'close' } })); // Toggle specific sidebar by ID document.dispatchEvent(new CustomEvent('basecoat:sidebar', { detail: { id: 'main-navigation' } })); // Open specific sidebar by ID document.dispatchEvent(new CustomEvent('basecoat:sidebar', { detail: { id: 'main-navigation', action: 'open' } })); ``` ### Initialization Event ```javascript document.addEventListener('basecoat:initialized', function(e) { if (e.target.matches('.sidebar')) { console.log('Sidebar initialized'); } }); ``` ### Listen for State Changes ```javascript const sidebar = document.querySelector('.sidebar'); // Create a MutationObserver to watch for aria-hidden changes const observer = new MutationObserver(function(mutations) { mutations.forEach(function(mutation) { if (mutation.attributeName === 'aria-hidden') { const isHidden = sidebar.getAttribute('aria-hidden') === 'true'; console.log('Sidebar is now:', isHidden ? 'hidden' : 'visible'); } }); }); observer.observe(sidebar, { attributes: true }); ``` ## Mobile Behavior ### Auto-Close on Navigation By default, clicking a link or button closes the sidebar on mobile. To prevent this: ```html <a href="#" data-keep-mobile-sidebar-open>Keep Sidebar Open</a> ``` ### Mobile Toggle Button ```html <header class="lg:hidden flex items-center gap-4 p-4 border-b"> <button type="button" class="btn-icon-ghost" aria-label="Toggle navigation" onclick="document.dispatchEvent(new CustomEvent('basecoat:sidebar'))" > <svg class="size-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> <line x1="4" x2="20" y1="12" y2="12"></line> <line x1="4" x2="20" y1="6" y2="6"></line> <line x1="4" x2="20" y1="18" y2="18"></line> </svg> </button> <h1>Page Title</h1> </header> ``` ## Multiple Sidebars ### Left and Right Sidebars ```html <aside class="sidebar" id="main-nav" aria-hidden="false" data-side="left"> <nav><!-- Left sidebar content --></nav> </aside> <main> <button onclick="document.dispatchEvent(new CustomEvent('basecoat:sidebar', { detail: { id: 'main-nav' } }))"> Toggle Left </button> <button onclick="document.dispatchEvent(new CustomEvent('basecoat:sidebar', { detail: { id: 'filters' } }))"> Toggle Right </button> </main> <aside class="sidebar" id="filters" aria-hidden="true" data-side="right"> <nav><!-- Right sidebar content (filters, etc.) --></nav> </aside> ``` ## Accessibility Guidelines ### ARIA Requirements - Use `aria-label` on the `<nav>` element - Use `role="group"` and `aria-labelledby` for navigation groups - Use `role="heading"` for group labels with corresponding `id` - Manage `aria-hidden` for visibility state ### Keyboard Navigation - **Tab**: Navigate through interactive elements - **Enter/Space**: Activate links and buttons - **Escape**: Close sidebar on mobile ### Screen Reader Support ```html <aside class="sidebar" aria-hidden="false" aria-label="Main navigation"> <nav> <section aria-label="Navigation menu"> <!-- navigation items --> </section> </nav> </aside> ``` ## Best Practices ### Content Organization - Group related navigation items - Use clear, descriptive labels - Limit nesting depth (max 2 levels recommended) - Prioritize frequently used items at the top ### Visual Design - Maintain consistent icon sizes - Use active states for current page - Provide hover/focus states - Consider dark mode compatibility ### Performance - Lazy load sidebar content if complex - Use CSS transitions for smooth animations - Minimize JavaScript for basic functionality ### Mobile Considerations - Always provide a toggle button - Ensure adequate touch targets - Auto-close on navigation by default - Use overlay to indicate focus ## Jinja/Nunjucks Macro ### Using the Macro ```jinja {% from "sidebar.njk" import sidebar %} {% set menu = [ { type: "group", label: "Getting started", items: [ { label: "Playground", url: "#", icon: icon_terminal }, { label: "Models", url: "#", icon: icon_bot }, { label: "Settings", type: "submenu", icon: icon_settings, items: [ { label: "General", url: "#" }, { label: "Team", url: "#" }, { label: "Billing", url: "#" } ]} ]} ] %} {{ sidebar( label="Sidebar navigation", content_attrs={"class": "scrollbar"}, menu=menu ) }} ``` ### Macro Parameters - `label`: Accessible label for the sidebar - `menu`: Array of navigation items - `content_attrs`: Additional attributes for the content section - `header`: Custom header content - `footer`: Custom footer content

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/GustavoGomezPG/basecoat-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server