Drawer

Display overlay area at any side of the screen
Import

Usage

import { useDisclosure } from '@mantine/hooks';
import { Drawer, Button, Group } from '@mantine/core';
function Demo() {
const [opened, { open, close }] = useDisclosure(false);
return (
<>
<Drawer opened={opened} onClose={close} title="Authentication">
{/* Drawer content */}
</Drawer>
<Group position="center">
<Button onClick={open}>Open Drawer</Button>
</Group>
</>
);
}

Position

Drawer can be placed on left (default), top, right and bottom. Control drawer position with position prop, for example <Drawer position="top" />.

Customize overlay

Drawer uses Overlay component, you can set any props that Overlay supports with overlayProps:

import { useDisclosure } from '@mantine/hooks';
import { Drawer, Group, Button } from '@mantine/core';
function Demo() {
const [opened, { open, close }] = useDisclosure(false);
return (
<>
<Drawer
opened={opened}
onClose={close}
title="Authentication"
overlayProps={{ opacity: 0.5, blur: 4 }}
>
{/* Drawer content */}
</Drawer>
<Group position="center">
<Button onClick={open}>Open drawer</Button>
</Group>
</>
);
}

Sizes

You can change drawer width/height (depends on position) by setting size prop to predefined size or any valid width, for example, size="55%" or size={200}:

<Drawer position="right" size="xl" /> // predefined xl width
<Drawer position="top" size={160} /> // 10rem height
<Drawer position="left" size="75%" /> // 75% width

Remove header

To remove header set withCloseButton={false}

import { useDisclosure } from '@mantine/hooks';
import { Drawer, Group, Button } from '@mantine/core';
function Demo() {
const [opened, { open, close }] = useDisclosure(false);
return (
<>
<Drawer opened={opened} onClose={close} withCloseButton={false}>
Drawer without header, press escape or click on overlay to close
</Drawer>
<Group position="center">
<Button onClick={open}>Open Drawer</Button>
</Group>
</>
);
}

Drawer with scroll

import { useDisclosure } from '@mantine/hooks';
import { Drawer, Group, Button } from '@mantine/core';
function Demo() {
const [opened, { open, close }] = useDisclosure(false);
const content = Array(100)
.fill(0)
.map((_, index) => <p key={index}>Drawer with scroll</p>);
return (
<>
<Drawer opened={opened} onClose={close} title="Header is sticky">
{content}
</Drawer>
<Group position="center">
<Button onClick={open}>Open drawer</Button>
</Group>
</>
);
}

Usage with ScrollArea

import { useDisclosure } from '@mantine/hooks';
import { Drawer, Group, Button } from '@mantine/core';
function Demo() {
const [opened, { open, close }] = useDisclosure(false);
const content = Array(100)
.fill(0)
.map((_, index) => <p key={index}>Drawer with scroll</p>);
return (
<>
<Drawer
opened={opened}
onClose={close}
title="Header is sticky"
scrollAreaComponent={ScrollArea.Autosize}
>
{content}
</Drawer>
<Group position="center">
<Button onClick={open}>Open drawer</Button>
</Group>
</>
);
}

Change transition

Drawer is built with Transition component. Use transitionProps prop to customize any Transition properties:

import { useDisclosure } from '@mantine/hooks';
import { Drawer, Button, Group } from '@mantine/core';
function Demo() {
const [opened, { open, close }] = useDisclosure(false);
return (
<>
<Drawer
opened={opened}
onClose={close}
title="Authentication"
transitionProps={{ transition: 'rotate-left', duration: 150, timingFunction: 'linear' }}
>
{/* Drawer content */}
</Drawer>
<Group position="center">
<Button onClick={open}>Open Drawer</Button>
</Group>
</>
);
}

Initial focus

Drawer uses FocusTrap to trap focus. Add data-autofocus attribute to the element that should receive initial focus.

import { useDisclosure } from '@mantine/hooks';
import { Drawer, Group, Button, TextInput } from '@mantine/core';
function Demo() {
const [opened, { open, close }] = useDisclosure(false);
return (
<>
<Drawer opened={opened} onClose={close} title="Focus demo">
<TextInput label="First input" placeholder="First input" />
<TextInput
data-autofocus
label="Input with initial focus"
placeholder="It has data-autofocus attribute"
mt="md"
/>
</Drawer>
<Group position="center">
<Button onClick={open}>Open drawer</Button>
</Group>
</>
);
}

Control behavior

The following props can be used to control Drawer behavior. In most cases it is not recommended to turn these features off – it will make the component less accessible.

  • trapFocus – determines whether focus should be trapped inside drawer
  • closeOnEscape – determines whether the drawer should be closed when Escape key is pressed
  • closeOnClickOutside – determines whether the drawer should be closed when user clicks on the overlay
  • returnFocus – determines whether focus should be returned to the element that was focused before the drawer was opened

Compound components

You can use the following compound components to have full control over the Drawer rendering:

  • Drawer.Root – context provider
  • Drawer.Overlay – render Overlay
  • Drawer.Content – main drawer element, should include all drawer content
  • Drawer.Header – sticky header, usually contains Drawer.Title and Drawer.CloseButton
  • Drawer.Titleh2 element, aria-labelledby of Drawer.Content is pointing to this element, usually is rendered inside Drawer.Header
  • Drawer.CloseButton – close button, usually rendered inside Drawer.Header
  • Drawer.Body – a place for main content, aria-describedby of Drawer.Content is pointing to this element
import { useDisclosure } from '@mantine/hooks';
import { Drawer, Button, Group } from '@mantine/core';
function Demo() {
const [opened, { open, close }] = useDisclosure(false);
return (
<>
<Drawer.Root opened={opened} onClose={close}>
<Drawer.Overlay />
<Drawer.Content>
<Drawer.Header>
<Drawer.Title>Drawer title</Drawer.Title>
<Drawer.CloseButton />
</Drawer.Header>
<Drawer.Body>Drawer content</Drawer.Body>
</Drawer.Content>
</Drawer.Root>
<Group position="center">
<Button onClick={open}>Open drawer</Button>
</Group>
</>
);
}

Fixed elements offset

Drawer component uses react-remove-scroll package to lock scroll. To properly size these elements add a className to them (documentation):

import { RemoveScroll } from '@mantine/core';
// to make "width: 100%"
<div className={RemoveScroll.classNames.fullWidth} />
// to make "right: 0"
<div className={RemoveScroll.classNames.zeroRight} />

Accessibility

Drawer component follows WAI-ARIA recommendations on accessibility.

Labels

Set title props to make component accessible, will add aria-labelledby to the content element:

import { Drawer } from '@mantine/core';
function Demo() {
return <Drawer title="Drawer label" opened onClose={() => {}} />;
}

To set close button aria-label use closeButtonProps:

import { Drawer } from '@mantine/core';
function Demo() {
return <Drawer closeButtonProps={{ 'aria-label': 'Close modal' }} opened onClose={() => {}} />;
}

Keyboard interactions

KeyDescription
EscapeClose modal

Drawer component props

NameTypeDescription
children
ReactNode
Modal content
closeButtonProps
ModalBaseCloseButtonProps
Props added to close button
closeOnClickOutside
boolean
Determines whether the modal/drawer should be closed when user clicks on the overlay, true by default
closeOnEscape
boolean
Determines whether onClose should be called when user presses escape key, true by default
id
string
Id used to connect modal/drawer with body and title
keepMounted
boolean
If set modal/drawer will not be unmounted from the DOM when it is hidden, display: none styles will be added instead
lockScroll
boolean
Determines whether scroll should be locked when opened={true}, defaults to true
onClose *
() => void
Called when modal/drawer is closed
opened *
boolean
Determines whether modal/drawer is opened
overlayProps
ModalBaseOverlayProps
Props added to Overlay component, use configure opacity, background color, styles and other properties
padding
number | "xs" | "sm" | "md" | "lg" | "xl"
Key of theme.spacing or any valid CSS value to set content, header and footer padding, 'md' by default
portalProps
Omit<PortalProps, "children" | "target" | "withinPortal">
Props to pass down to the portal when withinPortal is true
position
"bottom" | "left" | "right" | "top"
Side of the screen where drawer will be opened, 'left' by default
returnFocus
boolean
Determines whether focus should be returned to the last active element onClose is called, true by default
scrollAreaComponent
ScrollAreaComponent
Scroll area component, ScrollArea.Autosize by default
shadow
MantineShadow
Key of theme.shadows or any valid css box-shadow value, 'xl' by default
size
number | "xs" | "sm" | "md" | "lg" | "xl"
Controls content width, 'md' by default
target
string | HTMLElement
Target element or selector where Portal should be rendered, by default new element is created and appended to the document.body
title
ReactNode
Modal title
transitionProps
Partial<Omit<TransitionProps, "mounted">>
Props added to Transition component that used to animate overlay and body, use to configure duration and animation type, { duration: 200, transition: 'pop' } by default
trapFocus
boolean
Determines whether focus should be trapped, true by default
withCloseButton
boolean
Determines whether close button should be rendered, true by default
withOverlay
boolean
Determines whether overlay should be rendered, true by default
withinPortal
boolean
Determines whether component should be rendered inside Portal, true by default
zIndex
number
z-index CSS property of root element, 200 by default

Drawer component Styles API

NameStatic selectorDescription
root.mantine-Drawer-rootRoot element
inner.mantine-Drawer-innerElement used to position drawer, has fixed position, takes entire screen
content.mantine-Drawer-contentDrawer.Content root element
header.mantine-Drawer-headerContains title and close button
overlay.mantine-Drawer-overlayOverlay displayed under the Drawer.Content
title.mantine-Drawer-titleDrawer title (h2 tag), displayed in header
body.mantine-Drawer-bodyDrawer body, displayed after header
close.mantine-Drawer-closeClose button