Sidebar navigation component with brand area, scrollable nav, and pinned footer.
Provides three components:
sidebar/1— collapsible 240 px aside with:default/:darkvariantssidebar_item/1— navigation link with active highlight, icon, and badgesidebar_section/1— groups nav items under an uppercase section label
Example
<.sidebar variant={:default}>
<:brand>
<img src="/logo.svg" alt="Acme" class="h-6 w-auto" />
</:brand>
<:nav_items>
<.sidebar_section label="Main Menu">
<.sidebar_item href="/dashboard" active={@live_action == :index}>
Dashboard
</.sidebar_item>
</.sidebar_section>
</:nav_items>
<:footer_items>
<.sidebar_item href="/settings">Settings</.sidebar_item>
</:footer_items>
</.sidebar>
Summary
Functions
Responsive sidebar with brand area, scrollable nav, and pinned footer.
A navigation link inside the sidebar.
Collapsible sidebar section using native <details>/<summary>.
Groups sidebar navigation items under an optional section label.
Functions
Responsive sidebar with brand area, scrollable nav, and pinned footer.
The sidebar is always 240 px wide (set on the CSS Grid column). On desktop
it is a static grid cell with flex flex-col and border-r. On mobile the
parent shell/1 component manages its visibility as an overlay.
The layout is a vertical flex container divided into three parts:
┌──────────────────────────┐ ← h-14 brand area (shrink-0, border-b)
│ brand slot │
├──────────────────────────┤
│ │ ← flex-1, overflow-y-auto
│ nav_items slot │
│ │
├──────────────────────────┤ ← shrink-0, border-t
│ footer_items slot │
└──────────────────────────┘Example
<.sidebar variant={:default}>
<:brand>
<img src="/logo.svg" alt="Acme" class="h-6 w-auto" />
</:brand>
<:nav_items>
<.sidebar_item href="/dashboard" active>Dashboard</.sidebar_item>
</:nav_items>
<:footer_items>
<.sidebar_item href="/settings">Settings</.sidebar_item>
</:footer_items>
</.sidebar>Attributes
id(:string) - Element ID used bymobile_sidebar_toggle/1'sJS.toggle/1call. Keep the default unless you render multiple shells on the same page.Defaults to
"sidebar-drawer".collapsed(:boolean) - Whentrue, translates the sidebar off-screen via-translate-x-full. Useful for programmatic collapse without the mobile overlay pattern.Defaults to
false.class(:string) - Additional CSS classes. Defaults tonil.variant(:atom) - Visual variant for the sidebar background.:default— uses--sidebar-backgroundand--sidebar-foregroundtokens, which respect the current color theme and dark mode.:dark— forces a dark background regardless of color mode. Appliesdark bg-sidebar-background text-sidebar-foregroundclasses directly, producing the "always dark" look used by tools like Vercel or Linear.
Defaults to
:default. Must be one of:default, or:dark.Global attributes are accepted. HTML attributes forwarded to the aside element.
Slots
brand- Logo or application name area rendered at the top of the sidebar inside ah-14row that aligns with the topbar height. Typically holds a wordmark, icon-plus-name combo, or workspace switcher.nav_items- Primary navigation items (the main middle section of the sidebar). This slot is placed in anoverflow-y-auto<nav>element so that long navigation lists scroll independently of the footer. Usesidebar_section/1andsidebar_item/1inside this slot.footer_items- Secondary items anchored to the bottom of the sidebar (above the fold). Typically holds Settings and Help links. Rendered in ashrink-0div with a top border separating it from the primary nav.inner_block- Fallback slot for fully custom sidebar content when the named slots (:brand,:nav_items,:footer_items) do not provide enough structure. Only rendered when:nav_itemsis empty.
A navigation link inside the sidebar.
Renders a full-width anchor element with:
- Active state highlighting via
bg-accent text-accent-foreground - Optional leading icon in its own
shrink-0container - Optional trailing badge count (circular pill with
bg-primary) - Keyboard focus outline inherited from the global focus ring tokens
Example
<%!-- Basic item --%>
<.sidebar_item href="/dashboard" active={@live_action == :index}>
Dashboard
</.sidebar_item>
<%!-- Item with icon and notification badge --%>
<.sidebar_item href="/inbox" active={@live_action == :inbox} badge={@unread}>
<:icon><.icon name="inbox" /></:icon>
Inbox
</.sidebar_item>Attributes
href(:string) - Navigation href for the anchor element. Defaults to"#".active(:boolean) - Highlights this item as the currently active route. Addsbg-accent text-accent-foregroundwhentrue. Typically derived from@live_action == :route_namein your LiveView.Defaults to
false.badge(:integer) - Optional notification badge count displayed on the right side of the item. Passnil(the default) to hide the badge entirely. Common for unread message counts, pending task counts, etc.Defaults to
nil.class(:string) - Additional CSS classes for the anchor element. Defaults tonil.Global attributes are accepted. HTML attributes forwarded to the anchor element.
Slots
icon- Optional icon displayed before the label. Use<.icon name="...">inside this slot. The icon is wrapped inshrink-0so it does not compress when the label is long.inner_block(required) - The text label for this navigation item.
Collapsible sidebar section using native <details>/<summary>.
Uses details-open:rotate-90 (Tailwind v4) for the animated chevron.
Zero JavaScript required — browser handles expand/collapse natively.
Example
<.sidebar_item_expandable label="Settings" active={@section == :settings}>
<.sidebar_item href="/settings/profile">Profile</.sidebar_item>
<.sidebar_item href="/settings/security">Security</.sidebar_item>
</.sidebar_item_expandable>Attributes
label(:string) (required) - Section label shown in the summary.active(:boolean) - Whentrue, auto-opens the details element via theopenattribute. Defaults tofalse.class(:string) - Additional CSS classes for the details element. Defaults tonil.- Global attributes are accepted.
Slots
icon- Optional icon displayed before the label.inner_block(required) - Nested sidebar_item/1 components.
Groups sidebar navigation items under an optional section label.
Use multiple sidebar_section/1 components inside the :nav_items slot of
sidebar/1 to create a visually separated, labelled hierarchy of links.
Section labels use text-xs uppercase tracking-wider for a compact
enterprise-style appearance. Items within the section are spaced with
space-y-0.5 for tight, scannable lists.
Example
<.sidebar_section label="Analytics">
<.sidebar_item href="/revenue" active={@live_action == :revenue}>
Revenue
</.sidebar_item>
<.sidebar_item href="/retention">Retention</.sidebar_item>
</.sidebar_section>Attributes
label(:string) - Section heading displayed in small uppercase muted text above the items. Passnilto render the items without any heading (useful for the first section where a heading is redundant).Defaults to
nil.class(:string) - Additional CSS classes for the section wrapper. Defaults tonil.Global attributes are accepted.
Slots
inner_block(required) - sidebar_item/1 components to group under this section.