OverlaysReact
A panel that slides in from the edge of the screen.
Rendered by React 19.3.1
Loading React…Installation
npm i @hamur/reactNot on npm yet. The package goes out under the chosen name.
Anatomy
Import the component and assemble its parts:
<Drawer.Root>
<Drawer.Trigger />
<Drawer.Portal>
<Drawer.Backdrop />
<Drawer.Viewport>
<Drawer.Popup>
<Drawer.Content>
<Drawer.Title />
<Drawer.Description />
<Drawer.Close />
</Drawer.Content>
</Drawer.Popup>
</Drawer.Viewport>
</Drawer.Portal>
</Drawer.Root>
// Not in this example: Drawer.Indent, Drawer.IndentBackground, Drawer.Provider, Drawer.SwipeArea, Drawer.VirtualKeyboardProviderExamples
Position
swipeDirection matches the side the drawer comes from.
Nested
A drawer opens another; data-nested-drawer-open and --nested-drawers style the ones behind.
Snap Points
snapPoints stops a bottom sheet at preset heights.
Virtual Keyboard Aware
VirtualKeyboardProvider keeps the focused field visible above a software keyboard.
Indent Provider
Provider, Indent and IndentBackground scale the page down while a drawer is open.
Non Modal
modal off and disablePointerDismissal keep the page usable and the drawer open.
Swipe Area
SwipeArea along the edge opens the drawer with a swipe.
API reference
31 props across 15 parts, in React syntax. className, style, render are listed once, under Shared props.
BackdropDrawer.Backdrop
An overlay displayed beneath the popup. Renders a <div>.
| Prop | Type | Default |
|---|---|---|
forceRenderWhether the backdrop is forced to render even when nested. | boolean | false |
| Data attribute | Description |
|---|---|
data-open | Present when the drawer is open. |
data-closed | Present when the drawer is closed. |
data-starting-style | Present when the drawer begins animating in. |
data-ending-style | Present when the drawer is animating out. |
| CSS variable | Description |
|---|---|
--drawer-swipe-progress | The swipe progress of the drawer gesture. |
CloseDrawer.Close
A button that closes the drawer. Renders a <button>.
| Prop | Type | Default |
|---|---|---|
nativeButtonWhether the component renders a native <button> element when replacing it | boolean | true |
| Data attribute | Description |
|---|---|
data-disabled | Present when the button is disabled. |
ContentDrawer.Content
A container for the drawer contents. Renders a <div>.
DescriptionDrawer.Description
A paragraph with additional information about the drawer. Renders a <p>.
IndentDrawer.Indent
A wrapper element intended to contain your app's main UI. Applies data-active when any drawer within the nearest <Drawer.Provider> is open. Renders a <div>.
IndentBackgroundDrawer.IndentBackground
An element placed before <Drawer.Indent> to render a background layer that can be styled based on whether any drawer is open. Renders a <div>.
PopupDrawer.Popup
A container for the drawer contents. Renders a <div>.
| Prop | Type | Default |
|---|---|---|
initialFocusDetermines the element to focus when the drawer is opened. | boolean | React.RefObject<HTMLElement | null> | ((openType: InteractionType) => boolean | void | HTMLElement | null) | — |
finalFocusDetermines the element to focus when the drawer is closed. | boolean | React.RefObject<HTMLElement | null> | ((closeType: InteractionType) => boolean | void | HTMLElement | null) | — |
| Data attribute | Description |
|---|---|
data-open | Present when the drawer is open. |
data-closed | Present when the drawer is closed. |
data-starting-style | Present when the drawer begins animating in. |
data-ending-style | Present when the drawer is animating out. |
data-expanded | Present when the drawer is at the expanded (full-height) snap point. |
data-nested-drawer-open | Present when a nested drawer is open. |
data-nested-drawer-swiping | Present when a nested drawer is being swiped. |
data-swipe-dismiss | Present when the drawer is dismissed by swiping. |
data-swipe-direction | Indicates the swipe direction. |
data-swiping | Present when the drawer is being swiped. |
| CSS variable | Description |
|---|---|
--nested-drawers | The number of nested drawers that are currently open. |
--drawer-height | The height of the drawer popup. |
--drawer-frontmost-height | The height of the frontmost open drawer in the current nested drawer stack. |
--drawer-swipe-movement-x | The swipe movement on the X axis. |
--drawer-swipe-movement-y | The swipe movement on the Y axis. |
--drawer-snap-point-offset | The snap point offset used for translating the drawer. |
--drawer-swipe-strength | A scalar (0.1-1) used to scale the swipe release transition duration in CSS. |
PortalDrawer.Portal
A portal element that moves the popup to a different part of the DOM. By default, the portal element is appended to <body>. Renders a <div>.
| Prop | Type | Default |
|---|---|---|
containerA parent element to render the portal element into. | HTMLElement | ShadowRoot | React.RefObject<HTMLElement | ShadowRoot | null> | null | — |
keepMountedWhether to keep the portal mounted in the DOM while the popup is hidden. | boolean | false |
ProviderDrawer.Provider
Provides a shared context for coordinating global Drawer UI, such as indent/background effects based on whether any Drawer is open. Doesn’t render its own element.
| Prop | Type | Default |
|---|---|---|
children | React.ReactNode | — |
RootDrawer.Root
Groups all parts of the drawer. Doesn’t render its own element.
| Prop | Type | Default |
|---|---|---|
defaultOpenWhether the drawer is initially open. | boolean | false |
openWhether the drawer is currently open. | boolean | — |
onOpenChangeEvent handler called when the drawer is opened or closed. | ((open: boolean, eventDetails: DrawerRootChangeEventDetails) => void) | — |
snapPointsSnap points used to position the drawer. | DrawerSnapPoint[] | — |
defaultSnapPointThe initial snap point value when uncontrolled. | DrawerSnapPoint | null | — |
snapPointThe currently active snap point. | DrawerSnapPoint | null | — |
onSnapPointChangeCallback fired when the snap point changes. | ((snapPoint: DrawerSnapPoint | null, eventDetails: DrawerRootSnapPointChangeEventDetails) => void) | — |
actionsRefA ref to imperative actions. | React.RefObject<DrawerRootActions | null> | — |
defaultTriggerIdID of the trigger that the drawer is associated with. | string | null | — |
disablePointerDismissalWhether to prevent the drawer from closing on outside presses. | boolean | false |
handleA handle to associate the drawer with a trigger. | DrawerHandle<Payload> | — |
modalDetermines if the drawer enters a modal state when open. | boolean | "trap-focus" | true |
onOpenChangeCompleteEvent handler called after any animations complete when the drawer is opened or closed. | ((open: boolean) => void) | — |
snapToSequentialPointsDisables velocity-based snap skipping so drag distance determines the next snap point. | boolean | false |
swipeDirectionThe swipe direction used to dismiss the drawer. | SwipeDirection | 'down' |
triggerIdID of the trigger that the drawer is associated with. | string | null | — |
childrenThe content of the drawer. | React.ReactNode | PayloadChildRenderFunction<Payload> | — |
SwipeAreaDrawer.SwipeArea
An invisible area that listens for swipe gestures to open the drawer. Renders a <div>.
| Prop | Type | Default |
|---|---|---|
swipeDirectionThe swipe direction that opens the drawer. | SwipeDirection | — |
disabledWhether the swipe area is disabled. | boolean | false |
| Data attribute | Description |
|---|---|
data-open | Present when the drawer is open. |
data-closed | Present when the drawer is closed. |
data-disabled | Present when the swipe area is disabled. |
data-swipe-direction | Indicates the swipe direction. |
data-swiping | Present when the drawer is being swiped. |
TitleDrawer.Title
A heading that labels the drawer. Renders a <h2>.
TriggerDrawer.Trigger
A button that opens the drawer. Renders a <button>.
| Prop | Type | Default |
|---|---|---|
handleA handle to associate the trigger with a drawer. | DrawerHandle<Payload> | — |
nativeButtonWhether the component renders a native <button> element when replacing it | boolean | true |
payloadA payload to pass to the drawer when it is opened. | Payload | — |
idID of the trigger. | string | — |
| Data attribute | Description |
|---|---|
data-disabled | Present when the trigger is disabled. |
data-popup-open | Present when the corresponding dialog is open. |
ViewportDrawer.Viewport
A positioning container for the drawer popup that can be made scrollable. Renders a <div>.
| Data attribute | Description |
|---|---|
data-open | Present when the drawer is open. |
data-closed | Present when the drawer is closed. |
data-starting-style | Present when the drawer begins animating in. |
data-ending-style | Present when the drawer is animating out. |
data-nested | Present when the drawer is nested within another drawer. |
| CSS variable | Description |
|---|---|
--drawer-keyboard-inset | The software keyboard inset, measured from the bottom edge of the layout viewport.
Present only when the drawer is wrapped in Drawer.VirtualKeyboardProvider. |
VirtualKeyboardProviderDrawer.VirtualKeyboardProvider
Provides keyboard-aware focus and scroll handling for bottom-sheet drawers with form fields.
| Prop | Type | Default |
|---|---|---|
children | React.ReactNode | — |
Shared props
Every part that renders an element takes these.
| Prop | Type |
|---|---|
classNameCSS class applied to the element, or a function that
returns a class based on the component's state. | string | ((state: State) => string | undefined) |
styleStyle applied to the element, or a function that
returns a style object based on the component's state. | React.CSSProperties | ((state: State) => React.CSSProperties | undefined) |
renderAllows you to replace the component's HTML element
with a different tag, or compose it with another component. | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, State> |
Keyboard and accessibility
Keyboard
Drawer takes Dialog's keys: Escape closes it, and Tab stays inside the popup while it is modal.
Accessibility
| Part | Sets | So that |
|---|---|---|
| Trigger | aria-haspopup="dialog", aria-expanded, aria-controls | a screen reader says the button opens a dialog and whether it is open |
| Popup | role="dialog", aria-labelledby to Title, aria-describedby to Description | the drawer is announced as a dialog with its heading and description |
| Popup | aria-hidden="true" on the rest of the page while modal is on | a screen reader stays inside the drawer |
| Backdrop | role="presentation" | the overlay is not read |
| SwipeArea | role="presentation", aria-hidden="true" | the invisible gesture area is not read or reached |
Focus order
- Opening moves focus to Popup, or to
initialFocus. TabandShift+Tabstay inside the popup while it is modal; withmodaloff, focus can leave.- Closing returns focus to the Trigger that opened it, or to
finalFocus.