Drawer
A panel that slides in from an edge and can be swiped away, for quick choices and detail on touch screens.
A drawer is a panel that slides in from the bottom (or another edge) and follows the finger: the reader can drag it away to close it. It suits quick choices and short detail on a phone. On a wide screen, where nobody swipes, a sheet or a dialog is usually the better fit. It is built on Base UI's drawer.
Extra contribution: none
// apps/docs/examples/ui/drawer.tsx'use client';
import {useState} from 'react';
import {formatCurrency} from '@workspace/active-format';import {Button} from '@workspace/active-ui/components/primitives/button';import { Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerTitle, DrawerTrigger,} from '@workspace/active-ui/components/primitives/drawer';
const AMOUNTS = [50, 100, 250];// Amounts are written by active-format, in the language of the page.const euro = (amount: number) => formatCurrency({amount, currency: 'EUR'}, 'en', {decimals: 0});
/** * A panel that slides up from the bottom and can be swiped away, the shape * of a quick choice on a phone. The swipe handle shows that it can be * dragged; `swipeDirection="right"` makes a side panel of the same kind. */export default function DrawerExample() { const [amount, setAmount] = useState<number | null>(null); return ( <div className="flex flex-col items-center gap-4"> <div className="flex flex-wrap justify-center gap-2"> <Drawer showSwipeHandle> <DrawerTrigger render={<Button variant="outline" />}> Add a contribution </DrawerTrigger> <DrawerContent> <DrawerHeader> <DrawerTitle>Extra contribution</DrawerTitle> <DrawerDescription> Choose an amount; it is collected with the next payment. </DrawerDescription> </DrawerHeader> <div className="flex justify-center gap-2 p-4"> {AMOUNTS.map((value) => ( <DrawerClose key={value} render={<Button variant="outline" />} onClick={() => setAmount(value)} > {euro(value)} </DrawerClose> ))} </div> <DrawerFooter> <DrawerClose render={<Button variant="ghost" />}> Not now </DrawerClose> </DrawerFooter> </DrawerContent> </Drawer>
<Drawer swipeDirection="right"> <DrawerTrigger render={<Button variant="outline" />}> Open the side drawer </DrawerTrigger> <DrawerContent> <DrawerHeader> <DrawerTitle>Recent activity</DrawerTitle> <DrawerDescription> Swipe to the right, press Escape or click outside to close. </DrawerDescription> </DrawerHeader> <ul className="text-muted-foreground flex flex-col gap-2 p-4 text-sm"> <li>Statement sent to 214 participants</li> <li>Contribution rate changed to 7.5%</li> <li>Scheme renamed</li> </ul> </DrawerContent> </Drawer> </div> <p className="text-muted-foreground text-sm"> Extra contribution: {amount === null ? 'none' : euro(amount)} </p> </div> );}Usage#
import { Drawer, DrawerContent, DrawerDescription, DrawerHeader, DrawerTitle, DrawerTrigger,} from '@workspace/active-ui/components/primitives/drawer';
<Drawer showSwipeHandle> <DrawerTrigger render={<Button variant="outline" />}>Open</DrawerTrigger> <DrawerContent> <DrawerHeader> <DrawerTitle>Extra contribution</DrawerTitle> <DrawerDescription>Choose an amount.</DrawerDescription> </DrawerHeader> </DrawerContent></Drawer>;Anatomy#
Drawer: the state and the gesture.swipe(defaultDirection down) is the direction that closes it, and so the edge it comes from:downfrom the bottom,upfrom the top,leftandrightfrom the sides.modal(defaulttrue) adds the backdrop and makes the page inert.snaplets it rest at several heights.Points showdraws the handle.Swipe Handle DrawerandTrigger Drawer: open and close from any element.Close Drawer: the panel, with its backdrop when modal. It has no close button of its own: the gesture,Content Escape, a click outside and yourDrawerclose it.Close DrawerwithHeader DrawerandTitle Drawer, andDescription Drawer.Footer Drawer,Swipe Handle DrawerandOverlay Drawer: the partsPortal Draweralready renders, for a layout of your own.Content
What your application provides#
The title and description, and the actions inside.
A way to close that does not need the gesture: a
Drawerbutton, for readers who cannot swipe or do not know they can.Close
Accessibility and keyboard#
Modal by default: the focus moves inside, stays there, and returns to the trigger on close.
Escapecloses it. The swipe handle is decorative (aria-).hidden The panel is named by its title and described by its description.
API#
Drawer#
Import from @workspace/
Props marked Base UI are behaviour of the Base UI part this component is built on.
Props
- Type
boolean
Whether the drawer is currently open.
- Type
boolean- Default
false
Whether the drawer is initially open.
To render a controlled drawer, use the open prop instead.
- Type
DrawerSnap Point | null
The currently active snap point. Use with on to control the snap point.
- Type
DrawerSnap Point | null
The initial snap point value when uncontrolled.
- Type
string | null
ID of the trigger that the drawer is associated with. This is useful in conjunction with the default prop to create an initially open drawer.
- Type
boolean- Default
false
Whether to prevent the drawer from closing on outside presses. For non-modal drawers, this also prevents the drawer from closing when focus moves outside of it.
- Type
DrawerHandle<unknown>
A handle to associate the drawer with a trigger. If specified, allows detached triggers to control the drawer's open state. Can be created with the Drawer.createHandle() method.
- Type
"trap-focus" | boolean - Default
true
Determines if the drawer enters a modal state when open.
true: user interaction is limited to just the drawer: focus is trapped, document page scroll is locked, and pointer interactions on outside elements are disabled.false: user interaction with the rest of the document is allowed.'trap-: focus is trapped inside the drawer, but document page scroll is not locked and pointer interactions outside of it remain enabled.focus'
- Type
boolean- Default
false
Whether a handle is drawn at the edge, to show that the drawer can be swiped.
- Type
DrawerSnap Point[]
Snap points used to position the drawer. Use numbers between 0 and 1 to represent fractions of the viewport height, numbers greater than 1 as pixel values, or strings in px/rem units (for example, '148px' or '30rem').
- Type
boolean- Default
false
Disables velocity-based snap skipping so drag distance determines the next snap point.
- Type
SwipeDirection - Default
'down'
The swipe direction used to dismiss the drawer.
- Type
string | null
ID of the trigger that the drawer is associated with. This is useful in conjunction with the open prop to create a controlled drawer. There's no need to specify this prop when the drawer is uncontrolled (that is, when the open prop is not set).
- Type
RefObject<โฆ>
A ref to imperative actions.
unmount: Ends the closing phase of the drawer after an externally controlled closing animation finishes. CallpreventinUnmount On Close() onfirst, otherwise the drawer completes closing on its own. Whether it leaves the DOM is decided byOpen Change keepon the portal.Mounted close: Closes the drawer imperatively when called.
Events
Called by the component when something happens.
- Type
(open, eventDetails) => void
Event handler called when the drawer is opened or closed.
- Type
(snapPoint, event Details) => void
Callback fired when the snap point changes.
- Type
(open: boolean) => void
Event handler called after any animations complete when the drawer is opened or closed.
Takes only the props listed.
Other parts#
DrawerPortal
All props come from the Base UI part this component is built on.
Props
- Type
HTMLElementRefObject<โฆ> ShadowRoot null
A parent element to render the portal element into.
- Type
boolean- Default
false
Whether to keep the portal mounted in the DOM while the popup is hidden.
- Type
ComponentRender Fn<โฆ> ReactElement<โฆ>
Allows you to replace the component's HTML element with a different tag, or compose it with another component.
Accepts a React or a function that returns the element to render.
Other props, such as the standard attributes of the underlying element, className and ref, are passed through.
DrawerOverlay
All props come from the Base UI part this component is built on.
Props
- Type
boolean- Default
false
Whether the backdrop is forced to render even when nested.
- Type
ComponentRender Fn<โฆ> ReactElement<โฆ>
Allows you to replace the component's HTML element with a different tag, or compose it with another component.
Accepts a React or a function that returns the element to render.
Other props, such as the standard attributes of the underlying element, className and ref, are passed through.
DrawerTrigger
All props come from the Base UI part this component is built on.
Props
- Type
DrawerHandle<unknown>
A handle to associate the trigger with a drawer. Can be created with the Drawer.createHandle() method.
- Type
string
ID of the trigger. In addition to being forwarded to the rendered element, it is also used to specify the active trigger for drawers in controlled mode (with the Drawer.Root trigger prop).
- Type
unknown
A payload to pass to the drawer when it is opened.
- Type
ComponentRender Fn<โฆ> ReactElement<โฆ>
Allows you to replace the component's HTML element with a different tag, or compose it with another component.
Accepts a React or a function that returns the element to render.
Other props, such as the standard attributes of the underlying element, className and ref, are passed through.
DrawerClose
All props come from the Base UI part this component is built on.
Props
- Type
ComponentRender Fn<โฆ> ReactElement<โฆ>
Allows you to replace the component's HTML element with a different tag, or compose it with another component.
Accepts a React or a function that returns the element to render.
Other props, such as the standard attributes of the underlying element, className and ref, are passed through.
DrawerContent
All props come from the Base UI part this component is built on.
Props
- Type
booleanRefObject<HTMLElement | null> (closeType) => โฆ
Determines the element to focus when the drawer is closed.
false: Do not move focus.true: Move focus based on the default behavior (trigger or previously focused element).Ref: Move focus to the ref element.Object function: Called with the interaction type (mouse,touch,pen, orkeyboard). Return an element to focus,trueto use the default behavior, orfalse/undefinedto do nothing.
- Type
booleanRefObject<HTMLElement | null> (openType) => โฆ
Determines the element to focus when the drawer is opened.
false: Do not move focus.true: Move focus based on the default behavior (first tabbable element or popup).Ref: Move focus to the ref element.Object function: Called with the interaction type (mouse,touch,pen, orkeyboard). Return an element to focus,trueto use the default behavior, orfalse/undefinedto do nothing.
- Type
ComponentRender Fn<โฆ> ReactElement<โฆ>
Allows you to replace the component's HTML element with a different tag, or compose it with another component.
Accepts a React or a function that returns the element to render.
Other props, such as the standard attributes of the underlying element, className and ref, are passed through.
Parts that take only their elementโs attributes
Drawer: the attributes of aSwipe Handle <div>, with className and ref.Drawer: the attributes of aHeader <div>, with className and ref.Drawer: the attributes of its element, with className and ref, and Base UI'sTitle renderto use your own element.Drawer: the attributes of its element, with className and ref, and Base UI'sDescription renderto use your own element.
This page adapts the Drawer documentation of shadcn/ui (MIT licence) to this package; see Third-party notices.