Skip to content

Drawer

The Drawer component displays supplementary content in a modal panel that slides in from an edge of the viewport. It uses the native <dialog> element, associates its title with aria-labelledby, traps keyboard focus while open, and supports closing with the close button, the Escape key, or a click on the backdrop.

Use the Drawer component when you need to:

  • Show navigation or filters without leaving the current page
  • Reveal contextual details or settings
  • Present a short task with optional footer actions
  • Keep supporting content available without permanently occupying the layout

Project details

This drawer contains supporting information for the current page.

Press Escape, use the close button, or click the backdrop to close it.

The trigger’s id must exactly match the Drawer’s triggerId.

---
import { Drawer } from 'accessible-astro-components'
---
<button id="project-drawer-trigger" type="button">View project details</button>
<Drawer triggerId="project-drawer-trigger" title="Project details">
<p>This drawer contains additional information about the project.</p>
</Drawer>

Drawers open from the right by default. Use position to choose any viewport edge.

<Drawer triggerId="filters-trigger" title="Filters" position="left">
<form><!-- Filter controls --></form>
</Drawer>
<Drawer triggerId="notifications-trigger" title="Notifications" position="top">
<p>You have no unread notifications.</p>
</Drawer>

Set showFooter and fill the named footer slot to keep actions separate from scrollable drawer content.

<button id="settings-trigger" type="button">Edit settings</button>
<Drawer triggerId="settings-trigger" title="Settings" showFooter>
<form id="settings-form">
<!-- Settings fields -->
</form>
<Fragment slot="footer">
<button type="button" onclick="closeDrawer()">Cancel</button>
<button type="submit" form="settings-form">Save settings</button>
</Fragment>
</Drawer>

The drawer title is always a semantic <h2>. Use headingSize only to change its visual size, without changing the document outline.

<Drawer
triggerId="compact-drawer-trigger"
title="Quick settings"
headingSize="h4"
>
<!-- Drawer content -->
</Drawer>
PropTypeDefaultDescription
triggerIdstring-Required. ID of the element that opens the drawer
titlestring-Required. Drawer title and accessible name
position'right' | 'left' | 'top' | 'bottom''right'Viewport edge from which the drawer opens
closeTextstring'Close'Visually hidden accessible text for the close button
headingSize'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6''h6'Visual size of the semantic <h2> title
showFooterbooleanfalseWhether to render the named footer slot
classstring-Additional classes applied to the <dialog> element
Other HTML attributes--Passed through to the <dialog> element
SlotDescription
DefaultMain drawer content in the scrollable content area
footerOptional footer content rendered when showFooter is true
KeyAction
TabMoves focus to the next focusable element and wraps within the open drawer
Shift + TabMoves focus backward and wraps within the open drawer
EscapeCloses the drawer through the native dialog behavior
  • Uses a modal <dialog> opened with showModal()
  • Labels the dialog with its visible title through aria-labelledby
  • Gives the title initial focus so the drawer’s context is announced first
  • Uses a semantic <h2> for a predictable document outline
  • Keeps keyboard focus inside the open drawer
  • Provides customizable, visually hidden text for the close button
  • Prevents the page behind the drawer from scrolling while a dialog is open
  • Disables slide transitions when the user prefers reduced motion

Pass a custom class and target it from a global style block. Component selectors use :where(), so you can override them without high-specificity selectors.

<Drawer
class="project-drawer"
triggerId="project-drawer-trigger"
title="Project details"
>
<!-- Drawer content -->
</Drawer>
<style>
:global(.project-drawer) {
--drawer-transition-duration: 0.35s;
inline-size: min(32rem, 90vw);
}
:global(.project-drawer .drawer-header) {
background-color: var(--color-primary-bg);
}
:global(.project-drawer .drawer-content) {
padding: var(--space-l);
}
</style>
PropertyDefaultDescription
--drawer-transition-duration0.25sDuration of the drawer and backdrop transitions
--drawer-transition-easingvar(--animation-timing, cubic-bezier(0.165, 0.84, 0.44, 1))Easing used by drawer transitions

Open each example to compare the available positions.

Right drawer

This drawer uses the default right position.

Left drawer

This drawer enters from the inline start edge.

Top drawer

This drawer enters from the top of the viewport.

Bottom drawer

This drawer enters from the bottom of the viewport.

  • Modal for focused content in a centered dialog
  • Accordion for non-modal progressive disclosure within the page