Drawer
Panel that slides in from an edge of the screen.
- Browsers
- Chrome 123+Firefox 121+Safari 17.5+
- Tier
- 0
- Bundle compressed
- 4.01 kB
- Forced layout budget
- 0 ms
- Axe budget
- 0
- SSR compatible
- Yes
- Built on
- elements/dialog
- Published contract
- Test harness
Playground
API
DrawerPanel
| Prop | Type | Default | Description |
|---|---|---|---|
size | "sm" | "md" | "lg" | "full" | "md" | Desktop widths: 24rem, 32rem, 40rem or available width. On mobile every size becomes a vertical bottom sheet. |
dismiss | "any" | "closerequest" | "none" | "any" | Native dismissal policy. Any permits backdrop, Escape and mobile downward swipe; none requires an explicit close control. |
backdrop | "opaque" | "transparent" | "opaque" | Backdrop appearance; does not change modal semantics. |
footer | ReactNode | — | Actions following the scrollable body. |
id* | string | — | Unique dialog id that the trigger and close button target, so the drawer opens and closes before hydration. |
trigger* | ReactNode | — | Content of the button that opens the drawer. |
title* | ReactNode | — | Heading rendered inside the drawer and used as its accessible name. |
description | ReactNode | — | Supporting text rendered under the title and referenced by aria-describedby. |
children | ReactNode | — | Body content placed between the description and the close button. |
side | "top" | "right" | "bottom" | "left" | "bottom" | Edge the drawer slides in from. |
closeLabel | string | "Close" | Accessible label for the circular close icon. |
className | string | — | Class applied to the dialog element. |
Drawer.Root (client)
| Prop | Type | Default | Description |
|---|---|---|---|
open | boolean | — | Controlled open state. |
defaultOpen | boolean | — | Uncontrolled initial open state. |
onOpenChange | DialogChangeHandler | — | Called with the next open state and the details of what caused the change. |
side | "top" | "right" | "bottom" | "left" | "bottom" | Edge the drawer slides in from, which also sets the drag axis. |
modal | boolean | true | Open with showModal() so the rest of the page is inert behind a backdrop. |
dismissible | boolean | true | Allow a drag past the last snap point to close the drawer. |
snapPoints | readonly number[] | — | Fractions of the drawer size the panel settles on when dragged. |
activeSnapPoint | number | — | Controlled snap point, as one of the values in snapPoints. |
defaultActiveSnapPoint | number | — | Uncontrolled initial snap point. |
onSnapChange | (snap: number) => void | — | Called with the snap point the drawer settled on. |
children | ReactNode | — | The Trigger, Content and inner parts. |
Drawer.Trigger (client)
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | — | Class applied to the trigger button. |
onClick | (event: MouseEvent<HTMLButtonElement>) => void | — | Called when the trigger is clicked, before the drawer opens. |
ref | Ref<HTMLButtonElement> | — | Ref to the trigger button, which is refocused when the drawer closes. |
children | ReactNode | — | Content of the trigger button. |
Drawer.Content (client)
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | — | Class applied to the dialog element. |
style | CSSProperties | — | Inline style merged with the drag transform the drawer applies. |
onCancel | ReactEventHandler<HTMLDialogElement> | — | Called on the native dialog cancel event, such as pressing Escape. |
onClose | ReactEventHandler<HTMLDialogElement> | — | Called on the native dialog close event. |
ref | Ref<HTMLDialogElement> | — | Ref to the dialog element. |
children | ReactNode | — | Content of the drawer. |
Drawer.Title (client)
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | — | Class applied to the title element. |
children | ReactNode | — | Content of the title, which becomes the drawer's accessible name. |
Drawer.Description (client)
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | — | Class applied to the description element. |
children | ReactNode | — | Content of the description, referenced by aria-describedby. |
Drawer.Close (client)
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | — | Class applied to the close button. |
onClick | (event: MouseEvent<HTMLButtonElement>) => void | — | Called when the close button is clicked, before the drawer closes. |
children | ReactNode | — | Content of the close button. |
Drawer.Handle (client)
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | — | Class applied to the drag handle. |
onPointerDown | (event: PointerEvent<HTMLDivElement>) => void | — | Called when a drag starts on the handle. |
onPointerMove | (event: PointerEvent<HTMLDivElement>) => void | — | Called as the pointer moves during a drag. |
onPointerUp | (event: PointerEvent<HTMLDivElement>) => void | — | Called when the drag ends and the drawer settles on a snap point. |
onPointerCancel | (event: PointerEvent<HTMLDivElement>) => void | — | Called when the browser cancels the drag. |
Keyboard
| Key | Action |
|---|---|
| Enter / Space | Open the dialog from its trigger or activate Close |
| Escape | Request dismissal unless dismiss is none |
| Tab / Shift+Tab | Move within the modal dialog |
Accessibility
DrawerPanel uses a dialog with target ids, so opening, dismissal, focus containment and focus return work before hydration; dismiss controls backdrop and Escape. Panels come in sm, md, lg and full widths and become bottom sheets on phones. Swipe starts on the handle or header, so the body still scrolls. The client API adds controlled state and snap points.
Styling hooks
data-uiify-drawerdata-partdata-sidedata-sizedata-backdropdata-statedata-dragging--uiify-drawer-inline-size--uiify-drawer-transform--uiify-sheet-offset