Drawer
A headless, accessible slide-out drawer panel with focus trapping, scroll lock, and directional positioning.
Features
- Directional slide
- Focus trapping
- Focus restoration
- Scroll lock
- Escape key dismissal
- Controlled or uncontrolled open state
- Headless styling
Installation
npm install @ariaui/drawer
Examples
Slide-out panel with scroll lock and focus trap. Directional positioning props plus Tailwind on className.
Slide-out drawer
A right-aligned drawer with form fields, footer actions, and a dismiss button.
No preview output yet.
Drawer sides
Four drawer triggers that open panels from the top, right, bottom, and left side of the viewport.
No preview output yet.
Framer Motion
Four side drawers using Framer Motion through Overlay and Content asChild composition.
No preview output yet.
Anatomy
import * as Drawer from "@ariaui/drawer";
export default function Example() {
return (
<Drawer.Root>
<Drawer.Trigger />
<Drawer.Portal>
<Drawer.Overlay />
<Drawer.Content>
<Drawer.Header>
<Drawer.Title />
<Drawer.Description />
</Drawer.Header>
<Drawer.Footer>
<Drawer.Cancel />
<Drawer.Action />
<Drawer.Close />
</Drawer.Footer>
</Drawer.Content>
</Drawer.Portal>
</Drawer.Root>
);
}
API Reference
Root
State container. Owns the open/closed state and provides context to all child components.
| Prop | Type | Default |
|---|---|---|
open | boolean | — |
defaultOpen | boolean | false |
onOpenChange | (open: boolean) => void | — |
Trigger
Button that opens the drawer. Acts as the focus restoration target when the drawer closes.
| Attribute | Values |
|---|---|
| aria-haspopup | dialog |
| aria-expanded | "true" when open, "false" when closed |
| aria-controls | ID of the Content element |
| [data-state] | "open" | "closed" |
Portal
Portals the overlay and content to document.body by default.
| Prop | Type | Default |
|---|---|---|
container | HTMLElement | document.body |
Overlay
Background backdrop behind the drawer content. Clicking it closes the drawer.
| Prop | Type | Default |
|---|---|---|
asChild | boolean | false |
| Attribute | Values |
|---|---|
| [data-state] | "open" | "closed" |
Content
Drawer panel with dialog ARIA semantics, focus trapping, Escape dismissal, and body scroll lock.
| Prop | Type | Default |
|---|---|---|
side | "top" | "right" | "bottom" | "left" | "bottom" |
asChild | boolean | false |
| Attribute | Values |
|---|---|
| role | dialog |
| aria-modal | true |
| aria-labelledby | ID of the Title element |
| aria-describedby | ID of the Description element |
| [data-state] | "open" | "closed" |
| [data-side] | "top" | "right" | "bottom" | "left" |
Header
Layout container for the drawer title and description.
Title
Accessible title for the drawer. Referenced by Content via aria-labelledby.
Description
Accessible description for the drawer. Referenced by Content via aria-describedby.
Close
Button that closes the drawer when clicked. Use for auxiliary close actions (e.g., X icon).
Cancel
Cancel button that closes the drawer when clicked. Use for secondary/destructive cancel actions.
| Attribute | Values |
|---|---|
| data-drawer-cancel | Present when rendered |
Action
Action button that calls the onClick handler, then closes the drawer (unless preventDefault is called). Use for primary confirmation actions.
| Attribute | Values |
|---|---|
| data-drawer-action | Present when rendered |
Keyboard
| Shortcut | Action |
|---|---|
| Esc | Close the drawer and return focus to the trigger. |
| Tab | Move focus to the next focusable element within the drawer (loops to first). |
| Shift+Tab | Move focus to the previous focusable element within the drawer (loops to last). |
| Enter/Space | Activate the focused button (trigger, close, or any action button). |
Accessibility
The Drawer component implements the WAI-ARIA Dialog (Modal) pattern adapted for slide-out panels:
Contentrenders withrole="dialog"andaria-modal="true"to mark the surface as modal.Contentis labelled viaaria-labelledbypointing toTitleandaria-describedbypointing toDescription.Triggerexposesaria-haspopup="dialog",aria-expanded, andaria-controlsfor assistive technology.- Focus is trapped within the drawer using FocusScope — Tab loops through focusable elements.
Escapecloses the drawer from any focusable element inside it.- Focus is restored to the trigger element when the drawer closes.
- Body scroll is locked while the drawer is open to prevent interaction with underlying content.