Drawer

Display overlay area at any side of the screen
Import

Usage

Drawer is wrapped in Portal component, it can be rendered only on client as createPortal is not available during server side rendering:

import React, { useState } from 'react';
import { Drawer, Button, Group } from '@mantine/core';
function Demo() {
const [opened, setOpened] = useState(false);
return (
<>
<Drawer
opened={opened}
onClose={() => setOpened(false)}
padding="md"
>
Press escape to close the drawer
</Drawer>
<Group position="center">
<Button onClick={() => setOpened(true)}>Open Drawer</Button>
</Group>
</>
);
}

Position

Drawer can be placed on left (default), top, right and bottom. Control drawer position with position prop:

<Drawer position="right" />

Sizes

Control drawer size by setting size prop. You can use predefined values (xs, sm, md, lg, xl, full) or set drawer body size with any valid css value, for example, 200px, 25%, calc(100% - 100px). Size controls width for left and right positions and height for top and bottom. Size cannot exceed 100% of width and 100vh of height.

<Drawer position="right" size="xl" /> // predefined xl width
<Drawer position="top" size={200} /> // 200px height
<Drawer position="left" size="75%" /> // 75% width
<Drawer position="bottom" size="500vh" /> // 100vh height as max-height is 100vh

You can get predefined sizes by importing DRAWER_SIZES:

import { DRAWER_SIZES } from '@mantine/core';
Prop valueDrawer width
xs180px
sm240px
md320px
lg360px
xl500px
full100%

Control behavior

You can change drawer behavior with props:

  • noOverlay – removes overlay
  • noFocusTrap – removes focus trap inside drawer body
  • noScrollLock – disables scroll lock
  • noCloseOnClickOutside – do not trigger onClose for outside clicks
  • noCloseOnEscape – do not trigger onClose for escape key press
import React, { useState } from 'react';
import { Drawer, Button, Group } from '@mantine/core';
function Demo() {
const [opened, setOpened] = useState(false);
return (
<>
<Drawer
opened={opened}
onClose={() => setOpened(false)}
padding="md"
noCloseOnClickOutside
noFocusTrap
noScrollLock
noOverlay
>
Press escape to close the drawer
</Drawer>
<Group position="center">
<Button onClick={() => setOpened(true)}>Open Drawer</Button>
</Group>
</>
);
}

Try combining these props to achieve desired behavior. Note that disabling some parts will break accessibility and usability.

Padding
Shadow
function Demo() {
const [opened, setOpened] = useState(false);
return (
<>
<Drawer opened={opened} onClose={() => setOpened(false)} padding="md" shadow="xs">
Press escape to close the drawer if you are trapped
</Drawer>
<Group position="center">
<Button onClick={() => setOpened(true)}>Open drawer</Button>
</Group>
</>
);
}

Change transition

Drawer is built with Transition component. You can customize transition, timing function and duration:

import React, { useState } from 'react';
import { Drawer, Button, Group } from '@mantine/core';
function Demo() {
const [opened, setOpened] = useState(false);
return (
<>
<Drawer
opened={opened}
onClose={() => setOpened(false)}
padding="md"
transition="rotate-left"
transitionDuration={250}
transitionTimingFunction="ease"
>
Press escape to close the drawer
</Drawer>
<Group position="center">
<Button onClick={() => setOpened(true)}>Open Drawer</Button>
</Group>
</>
);
}

Accessibility and usability

By default:

  • When drawer is opened focus is trapped inside and document.body scroll is locked in current position
  • When user clicks on overlay or presses escape drawer is closed
  • Drawer transitions use disabled when user prefers to reduce motion
  • Drawer body has aria-modal and role="dialog" attributes

Add aria-labelledby and aria-describedby for better screen readers support:

<Drawer aria-labelledby="drawer-title" aria-describedby="drawer-body">
<h1 id="drawer-title">Title</h1>
<div id="drawer-body">Body</div>
</Drawer>

Initial focus

Drawer uses use-focus-trap to manage focus. To specify initial focus element add data-autofocus attribute:

<Drawer>
<input />
{/* Second input in modal will have initial focus */}
<input data-autofocus />
<input />
</Drawer>