Drawer
A slide-in panel anchored to an edge of the viewport.
Examples
Section titled “Examples”Default
Section titled “Default”<> <Button label="Open drawer" onClick={() => setIsOpen(true)} /> <Drawer {...args} isOpen={isOpen} onOpenChange={setIsOpen}> <DrawerContent onClose={() => setIsOpen(false)} /> </Drawer></>Placement Variants
Section titled “Placement Variants”<> <div style={{display: 'flex', flexWrap: 'wrap', gap: 8}}> {placements.map(option => ( <Button key={option.placement} label={option.label} onClick={() => setPlacement(option.placement)} /> ))} </div> <Drawer isOpen={placement != null} label={`${placements.find(option => option.placement === placement)?.label ?? 'Right'} drawer`} onOpenChange={nextOpen => { if (!nextOpen) { setPlacement(null); } }} placement={activePlacement}> <DrawerContent onClose={() => setPlacement(null)} title={`${placements.find(option => option.placement === activePlacement)?.label ?? 'Right'} drawer`} /> </Drawer></>Custom Size
Section titled “Custom Size”<> <div style={{display: 'flex', flexWrap: 'wrap', gap: 8}}> <Button label="Open 480px drawer" onClick={() => setVariant('numeric')} /> <Button label="Open 60vw drawer" onClick={() => setVariant('string')} /> </div> <Drawer isOpen={variant != null} label="Custom size drawer" onOpenChange={nextOpen => { if (!nextOpen) { setVariant(null); } }} placement="end" size={variant === 'string' ? '60vw' : 480}> <DrawerContent onClose={() => setVariant(null)} title={variant === 'string' ? '60vw drawer' : '480px drawer'} /> </Drawer></>Unsaved Changes
Section titled “Unsaved Changes”<> <Button label="Edit profile" onClick={() => setIsOpen(true)} /> <Drawer {...args} isOpen={isOpen} onOpenChange={setIsOpen}> <Layout content={ <LayoutContent> <div style={{display: 'flex', flexDirection: 'column', gap: 16}}> <Text as="p" color="secondary"> Backdrop and Escape dismissal are disabled, so unsaved edits can only be discarded through an explicit action. </Text> <TextInput label="Display name" onChange={() => {}} value="Ada Lovelace" /> </div> </LayoutContent> } footer={ <LayoutFooter primaryButton={ <Button label="Save" onClick={() => setIsOpen(false)} variant="primary" /> } secondaryButton={ <Button label="Discard" onClick={() => setIsOpen(false)} /> } /> } header={<LayoutHeader title="Edit profile" />} /> </Drawer></>Imperative
Section titled “Imperative”<> <Button label="Show report" onClick={() => drawer.show( <Layout content={ <LayoutContent> <Text as="p" color="secondary"> The report is ready for review. </Text> </LayoutContent> } footer={ <LayoutFooter primaryButton={ <Button label="Close" onClick={drawer.hide} variant="primary" /> } /> } header={<LayoutHeader title="Generated report" />} />, ) } /> {drawer.element}</>Auto Focus
Section titled “Auto Focus”<> <Button label="Open drawer" onClick={() => setIsOpen(true)} /> <Drawer isOpen={isOpen} label="Auto focus drawer" onOpenChange={setIsOpen} size={400}> <Layout content={ <LayoutContent> <div style={{ display: 'flex', flexDirection: 'column', gap: 12, }}> <button data-autofocus="true" style={{alignSelf: 'flex-start'}} type="button"> Focused action </button> <TextInput label="Notes" onChange={() => {}} placeholder="Add notes" value="" /> </div> </LayoutContent> } footer={ <LayoutFooter primaryButton={ <Button label="Close" onClick={() => setIsOpen(false)} variant="primary" /> } /> } header={<LayoutHeader title="Auto focus" />} /> </Drawer></>Nested Content
Section titled “Nested Content”<> <Button label="Edit workspace" onClick={() => setIsOpen(true)} /> <Drawer {...args} isOpen={isOpen} onOpenChange={setIsOpen}> <Layout content={ <LayoutContent label="Workspace settings"> <div style={{ display: 'flex', flexDirection: 'column', gap: 16, }}> <TextInput label="Workspace name" onChange={() => {}} value="Research Operations" /> <TextInput label="Owner" onChange={() => {}} value="Ada Lovelace" /> {Array.from({length: 10}, (_, index) => ( <Text as="p" color="secondary" key={index}> Setting group {index + 1}: Configure access, notifications, and workflow defaults for this workspace. </Text> ))} </div> </LayoutContent> } footer={ <LayoutFooter primaryButton={ <Button label="Save" onClick={() => setIsOpen(false)} variant="primary" /> } secondaryButton={ <Button label="Cancel" onClick={() => setIsOpen(false)} /> } /> } header={ <LayoutHeader subtitle="Manage workspace metadata and defaults." title="Edit workspace" /> } /> </Drawer></>Drawer
Section titled “Drawer”A slide-in panel anchored to an edge of the viewport.
| Prop | Type | Default | Description |
|---|---|---|---|
children* | ReactNode | — | Drawer body content. |
className | string | — | Additional CSS class names applied to the drawer. |
data-testid | string | — | Test ID applied to the drawer. |
dismissBehavior | DrawerDismissBehavior | {isEscapeDismissEnabled: true, isBackdropDismissEnabled: true} | Controls whether Escape and backdrop clicks request dismissal. Pass a boolean to enable or disable both behaviors together. |
isOpen* | boolean | — | Whether the drawer is open. |
label* | string | — | Accessible label for the drawer. |
onOpenChange* | (isOpen: boolean) => void | — | Called when the drawer requests an open-state change. |
placement | "end" | "start" | "top" | "bottom" | 'end' | Edge of the viewport the drawer slides in from. |
ref | Ref<HTMLDialogElement> | — | Ref forwarded to the drawer element. |
size | number | string | — | Width (start/end) or height (top/bottom) of the drawer. |
style | CSSProperties | — | Inline styles applied to the drawer. |