# 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