SutraUI.Drawer (Sutra UI v0.3.0)

View Source

A collapsible drawer navigation component with mobile toggle support.

The drawer provides a responsive navigation panel that can be toggled open/closed. By default, drawers are closed on desktop and require a trigger button or programmatic control to open. Use the open attribute to make a drawer initially open.

It supports:

  • Mobile overlay mode with backdrop
  • Desktop persistent mode (via open attribute)
  • Left or right positioning
  • Collapsible submenu sections
  • Active page highlighting
  • Custom header and footer sections

JavaScript Hook

The drawer requires JavaScript for:

  • Mobile toggle functionality
  • Close on backdrop click
  • Close on click outside (when drawer is open)
  • Responsive breakpoint handling
  • Active page link detection and highlighting
  • Managing open/closed state

The component uses a colocated JavaScript hook that is initialized by providing a unique id attribute.

Click Outside to Close

When the drawer is open, clicking anywhere outside of it (except on trigger buttons) will automatically close the drawer. This provides an intuitive way to dismiss the drawer without requiring an explicit close button.

Examples

Basic drawer with trigger button

<.drawer_trigger for="main-drawer" /> <.drawer id="main-drawer">

</.drawer>

Drawer initially open on desktop

<.drawer_trigger for="app-drawer" /> <.drawer id="app-drawer" side="left" open> <:header> <div class="flex items-center gap-2 p-2">

<img src="/logo.svg" alt="Logo" class="w-8 h-8" />
<span class="font-semibold">My App</span>

</:header>

<.drawer_group label="Main"> <.drawer_item href="/">Home</.drawer_item> <.drawer_item href="/dashboard">Dashboard</.drawer_item> </.drawer_group>

<:footer> <.drawer_item href="/settings">Settings</.drawer_item> </:footer> </.drawer>

Drawer with collapsible sections

<.drawer_trigger for="nav-drawer" /> <.drawer id="nav-drawer"> <.drawer_group label="Navigation"> <.drawer_item href="/">Overview</.drawer_item>

<.drawer_submenu label="Projects" open>

<.drawer_item href="/projects/active">Active</.drawer_item>
<.drawer_item href="/projects/archived">Archived</.drawer_item>

</.drawer_submenu>

<.drawer_item href="/team">Team</.drawer_item> </.drawer_group> </.drawer>

Right-side drawer with custom trigger

<.drawer_trigger for="filter-drawer" variant="outline">

Toggle Filters

</.drawer_trigger> <.drawer id="filter-drawer" side="right"> <.drawer_group label="Filters"> <p>Filter options here...</p> </.drawer_group> </.drawer>

Programmatic Control

You can control the drawer state from JavaScript using custom events:

// Toggle drawer
document.dispatchEvent(new CustomEvent('sutra-ui:drawer', {
  detail: { id: 'main-drawer' }
}));

// Open drawer
document.dispatchEvent(new CustomEvent('sutra-ui:drawer', {
  detail: { id: 'main-drawer', action: 'open' }
}));

// Close drawer
document.dispatchEvent(new CustomEvent('sutra-ui:drawer', {
  detail: { id: 'main-drawer', action: 'close' }
}));

Accessibility

  • Uses semantic <aside> and <nav> elements
  • Includes proper ARIA labels and aria-hidden state
  • Sets inert attribute when closed to prevent keyboard navigation
  • Automatically manages focus when opened/closed
  • Active page links marked with aria-current="page"

Mobile Behavior

On mobile (below breakpoint):

  • Drawer becomes a full-screen overlay
  • Clicking outside the nav closes the drawer
  • Clicking links automatically closes the drawer
  • Use data-keep-mobile-drawer-open attribute to prevent auto-close on specific elements

CSS Variables

The drawer uses these CSS variables:

  • --drawer-width: Desktop drawer width (default: 16rem)
  • --drawer-mobile-width: Mobile drawer width (default: 18rem)
  • --drawer: Background color
  • --drawer-foreground: Text color
  • --drawer-accent: Hover/active background
  • --drawer-accent-foreground: Hover/active text color
  • --drawer-border: Border color
  • --drawer-ring: Focus ring color

Summary

Functions

Renders a drawer navigation component.

Renders a drawer group with an optional label/heading.

Renders a drawer navigation item (link).

Renders a separator/divider in the drawer.

Renders a collapsible drawer submenu.

Renders a button to toggle the drawer open/closed.

Functions

drawer(assigns)

Renders a drawer navigation component.

Attributes

  • id (required) - Unique identifier for the drawer (required for hook)
  • side - Which side to position the drawer ("left" or "right", default: "left")
  • open - Initial open state for desktop (default: false)
  • mobile_open - Initial open state for mobile (default: false)
  • breakpoint - Pixel width for mobile breakpoint (default: 768)
  • label - ARIA label for navigation (default: "Drawer navigation")
  • class - Additional CSS classes for the aside container

Slots

  • header - Optional header content (rendered in nav > header)
  • footer - Optional footer content (rendered in nav > footer)
  • inner_block (required) - Main drawer content (rendered in nav > section)

Toggle Button

Use drawer_trigger/1 to create a toggle button for the drawer:

<.drawer_trigger for="my-drawer" />
<.drawer id="my-drawer">
  <!-- drawer content -->
</.drawer>

Attributes

  • id (:string) (required) - Unique identifier for the drawer (required for hook).
  • side (:string) - Which side to position the drawer. Defaults to "left". Must be one of "left", "right", "top", or "bottom".
  • open (:boolean) - Initial open state for desktop. Defaults to false.
  • mobile_open (:boolean) - Initial open state for mobile. Defaults to false.
  • breakpoint (:integer) - Pixel width for mobile breakpoint. Defaults to 768.
  • label (:string) - ARIA label for navigation. Defaults to "Drawer navigation".
  • class (:string) - Additional CSS classes. Defaults to nil.

Slots

  • header - Optional header content.
  • footer - Optional footer content.
  • inner_block (required) - Main drawer content.

drawer_group(assigns)

Renders a drawer group with an optional label/heading.

Attributes

  • label - Optional heading text for the group
  • class - Additional CSS classes

Examples

<.drawer_group label="Navigation">
  <.drawer_item href="/">Home</.drawer_item>
  <.drawer_item href="/about">About</.drawer_item>
</.drawer_group>

<.drawer_group>
  <.drawer_item href="/settings">Settings</.drawer_item>
</.drawer_group>

Attributes

  • label (:string) - Optional heading for the group. Defaults to nil.
  • class (:string) - Additional CSS classes. Defaults to nil.

Slots

  • inner_block (required)

drawer_item(assigns)

Renders a drawer navigation item (link).

Attributes

  • href (required) - URL for the link
  • variant - Visual variant ("default" or "outline")
  • size - Size variant ("default", "sm", or "lg")
  • current - Whether this is the current page
  • class - Additional CSS classes
  • rest - Additional HTML attributes

Examples

<.drawer_item href="/">Home</.drawer_item>

<.drawer_item href="/dashboard" variant="outline">
  Dashboard
</.drawer_item>

<.drawer_item href="/settings" current>
  Settings
</.drawer_item>

<.drawer_item href="/profile" size="sm">
  Profile
</.drawer_item>

Attributes

  • href (:string) (required) - URL for the link.
  • variant (:string) - Visual variant. Defaults to "default". Must be one of "default", or "outline".
  • size (:string) - Size variant. Defaults to "default". Must be one of "default", "sm", or "lg".
  • current (:boolean) - Whether this is the current page. Defaults to false.
  • class (:string) - Additional CSS classes. Defaults to nil.
  • Global attributes are accepted. Additional HTML attributes. Supports all globals plus: ["target", "rel", "data-ignore-current", "data-keep-mobile-drawer-open"].

Slots

  • inner_block (required)

drawer_separator(assigns)

Renders a separator/divider in the drawer.

Examples

<.drawer_separator />

drawer_submenu(assigns)

Renders a collapsible drawer submenu.

Attributes

  • label (required) - Label text for the submenu
  • open - Whether the submenu is initially open (default: false)
  • class - Additional CSS classes

Examples

<.drawer_submenu label="Projects">
  <.drawer_item href="/projects/active">Active</.drawer_item>
  <.drawer_item href="/projects/archived">Archived</.drawer_item>
</.drawer_submenu>

<.drawer_submenu label="Admin" open>
  <.drawer_item href="/admin/users">Users</.drawer_item>
  <.drawer_item href="/admin/settings">Settings</.drawer_item>
</.drawer_submenu>

Attributes

  • label (:string) (required) - Label for the submenu.
  • open (:boolean) - Whether the submenu is initially open. Defaults to false.
  • class (:string) - Additional CSS classes. Defaults to nil.

Slots

  • inner_block (required)

drawer_trigger(assigns)

Renders a button to toggle the drawer open/closed.

Attributes

  • for (required) - The ID of the drawer to toggle
  • variant - Visual variant. One of primary, secondary, destructive, outline, ghost, link. Defaults to ghost.
  • size - Size variant. One of default, sm, lg, icon. Defaults to icon.
  • class - Additional CSS classes

Examples

Default icon button (hamburger menu)

<.drawer_trigger for="main-drawer" />

Custom variant and size

<.drawer_trigger for="main-drawer" variant="outline" size="sm" />

Custom content

<.drawer_trigger for="main-drawer" variant="primary"> <span>Menu</span> </.drawer_trigger>

Attributes

  • for (:string) (required) - ID of the drawer to toggle.
  • variant (:string) - Visual style variant. Defaults to "ghost". Must be one of "primary", "secondary", "destructive", "outline", "ghost", or "link".
  • size (:string) - Size variant. Defaults to "icon". Must be one of "default", "sm", "lg", or "icon".
  • class (:string) - Additional CSS classes. Defaults to nil.
  • Global attributes are accepted. Additional HTML attributes.

Slots

  • inner_block - Custom button content (defaults to hamburger icon).