JGuang

Drawer

Drawer · Mantine Core

Preview
npm install @mantine/core@9.7.1 @mantine/hooks@9.7.1

Drawer

Install: npm install @mantine/core@9.7.1 @mantine/hooks@9.7.1

Version and compatibility

Pinned Mantine Core 9.7.1 requires React and React DOM ^19.2.0 and matching @mantine/hooks@9.7.1, from the installed npm package's peerDependencies. Do not force it into React 18 or another incompatible version. Explain upgrade impact and agree on a plan with the project owner; do not hide conflicts with --force/--legacy-peer-deps. The native Provider enables theme.respectReducedMotion and uses forceColorScheme for light/dark.

Use case

Show supplementary content in a sliding panel.

Native props used by this example

These props are extracted from the local typechecked JSX and grouped by their owning native component. This is not an exhaustive prop list; see pinned source signatures and inheritance below.

Component propExplanation
Button.onClickLocal click handler; replace demo logic with an explicit business action.
Drawer.openedWhether the controlled region is open.
Drawer.onCloseRequest to close; update the host's open state.
Drawer.titleHeading content for this component.
Drawer.closeButtonPropsNative close-control props, including its accessible name.

Interaction and state checks

Current scenarios: Default. Check actual behavior after selecting supported disabled/error/read-only scenarios; components without those native states do not receive invented universal props. Verify keyboard focus and exits, then connect changed values through the native callback signature.

Business integration boundary

Keep the native Portal enabled inside this isolated iframe. A real app must test overlay stacking, Escape and focus restoration.

Host setup

Install pinned @mantine/core and @mantine/hooks, import @mantine/core/styles.css at the entry and use MantineProvider. The example's theme/variant are JGuang-authored host props, not universal native component APIs; forceColorScheme synchronizes the app theme. Native implementation source is a reading reference: use npm exports rather than copying internal engines. This batch covers Core, not dates/charts/forms extension packages. Detailed upstream prose remains English.

Runnable usage

import { useState } from 'react';
import * as M from '@mantine/core';
import '@mantine/core/styles.css';


function ComponentPreview({ variant = 'Default' }: { variant?: string }) {
const [open, setOpen] = useState(false);
const content = <M.Text>Build something beautiful / 构建美好的界面</M.Text>;
return <><M.Button onClick={() => setOpen(true)}>Open drawer</M.Button><M.Drawer opened={open} onClose={() => setOpen(false)} title="Details" closeButtonProps={{ "aria-label": "Close drawer / 关闭抽屉" }}>{content}</M.Drawer></>;
}
export default function Example({ variant = 'Default', theme = 'light' }: { variant?: string; theme?: 'light' | 'dark' }) {
return <M.MantineProvider forceColorScheme={theme} theme={{ respectReducedMotion: true }}><ComponentPreview variant={variant} /></M.MantineProvider>;
}

Preview states

Default

The example uses the native Mantine API. For supported input demos, change the local variant to Disabled, Invalid or Read only; these are example labels, not new component props. Keep the documented data, controlled values, stores and compound children when adapting the example.

Usage

Position

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

Offset

Set the offset prop to change the drawer offset from the edge of the viewport:

Customize overlay

Drawer uses the Overlay component. You can set any props that Overlay supports with overlayProps:

Sizes

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

import { Drawer } from '@mantine/core';

function Demo() {
  return (
    <Drawer position="right" size="xl" opened onClose={() => {}}>
      {/* Drawer content */}
    </Drawer>
  );
}

Remove header

To remove the header, set withCloseButton={false}

Drawer with scroll

Usage with ScrollArea

Change transition

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

onExitTransitionEnd and onEnterTransitionEnd

The onExitTransitionEnd and onEnterTransitionEnd props can be used to run code after the exit/enter transition is finished. For example, this is useful when you want to clear data after the drawer is closed:

Initial focus

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

If you do not want to focus any elements when the drawer is opened, use the FocusTrap.InitialFocus component to create a visually hidden element that will receive initial focus:

If you do not add the data-autofocus attribute and do not use FocusTrap.InitialFocus, the drawer will focus the first focusable element inside it which is usually the close button.

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

react-remove-scroll settings

Drawer uses react-remove-scroll package to lock scroll. You can pass props down to the RemoveScroll component with removeScrollProps:

import { Drawer } from '@mantine/core';

function Demo() {
  return (
    <Drawer
      removeScrollProps={{ allowPinchZoom: true }}
      opened
      onClose={() => {}}
    >
      {/* Drawer content */}
    </Drawer>
  );
}

Change close icon

Use closeButtonProps to customize close button:

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.Title – h2 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

Drawer.Stack

Use Drawer.Stack component to render multiple drawers at the same time. Drawer.Stack keeps track of opened drawers, manages z-index values, focus trapping and closeOnEscape behavior. Drawer.Stack is designed to be used with useDrawersStack hook.

Differences from using multiple Drawer components:

  • Drawer.Stack manages z-index values – drawers that are opened later will always have higher z-index value disregarding their order in the DOM
  • Drawer.Stack disables focus trap and Escape key handling for all drawers except the one that is currently opened
  • Drawers that are not currently opened are present in the DOM but are hidden with opacity: 0 and pointer-events: none
  • Only one overlay is rendered at a time

Note that Drawer.Stack can only be used with Drawer component. Components built with Drawer.Root and other compound components are not compatible with Drawer.Stack.

useDrawersStack hook

useDrawersStack hook provides an easy way to control multiple drawers at the same time. It accepts an array of unique drawers ids and returns an object with the following properties:

interface UseDrawersStackReturnType<T extends string> {
  // Current opened state of each drawer
  state: Record<T, boolean>;

  // Opens drawer with the given id
  open: (id: T) => void;

  // Closes drawer with the given id
  close: (id: T) => void;

  // Toggles drawer with the given id
  toggle: (id: T) => void;

  // Closes all drawers within the stack
  closeAll: () => void;

  // Returns props for drawer with the given id
  register: (id: T) => {
    opened: boolean;
    onClose: () => void;
    stackId: T;
  };
}

Example of using useDrawersStack with Drawer component:

import { Drawer, useDrawersStack } from '@mantine/core';

function Demo() {
  const stack = useDrawersStack(['first', 'second']);

  return (
    <>
      <Drawer {...stack.register('first')}>First</Drawer>
      <Drawer {...stack.register('second')}>Second</Drawer>
      <Button onClick={() => stack.open('first')}>Open first</Button>
    </>
  );
}

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';

function Demo() {
  return (
    <>
      <div className={RemoveScroll.classNames.fullWidth}>
        width: 100%
      </div>
      <div className={RemoveScroll.classNames.zeroRight}>
        right: 0
      </div>
    </>
  );
}

Accessibility

Drawer component follows WAI-ARIA recommendations on accessibility.

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 drawer' }}
      opened
      onClose={() => {}}
    />
  );
}

Source-backed parameter reference

Implementation signatures and types are generated from the pinned local source. Optional props, native inherited types, union branches and never exclusions are preserved. A forwardRef implementation's ref is a React reference, not an additional business prop.

Drawer(_props)
export type DrawerStylesNames = DrawerRootStylesNames;

export type DrawerCssVariables = DrawerRootCssVariables;

export interface DrawerProps extends DrawerRootProps {
  /** Drawer title */
  title?: React.ReactNode;

  /** If set, the overlay is displayed @default true */
  withOverlay?: boolean;

  /** Props passed down to the `Overlay` component, can be used to configure opacity, `background-color`, styles and other properties */
  overlayProps?: ModalBaseOverlayProps;

  /** Drawer content */
  children?: React.ReactNode;

  /** If set, the close button is displayed @default true */
  withCloseButton?: boolean;

  /** Props passed down to the close button */
  closeButtonProps?: ModalBaseCloseButtonProps;

  /** Id of the drawer in the `Drawer.Stack` */
  stackId?: string;
}

export type DrawerFactory = Factory<{
  props: DrawerProps;
  ref: HTMLDivElement;
  stylesNames: DrawerStylesNames;
  vars: DrawerCssVariables;
  staticComponents: {
    Root: typeof DrawerRoot;
    Overlay: typeof DrawerOverlay;
    Content: typeof DrawerContent;
    Body: typeof DrawerBody;
    Header: typeof DrawerHeader;
    Title: typeof DrawerTitle;
    CloseButton: typeof DrawerCloseButton;
    Stack: typeof DrawerStack;
  };
}>;

Native and external types

External types remain defined by React or native dependencies, not manually expanded into guessed props. The installed version's TypeScript definitions are authoritative.

Factory<{
  props: DrawerProps;
  ref: HTMLDivElement;
  stylesNames: DrawerStylesNames;
  vars: DrawerCssVariables;
  staticComponents: {
    Root: typeof DrawerRoot;
    Overlay: typeof DrawerOverlay;
    Content: typeof DrawerContent;
    Body: typeof DrawerBody;
    Header: typeof DrawerHeader;
    Title: typeof DrawerTitle;
    CloseButton: typeof DrawerCloseButton;
    Stack: typeof DrawerStack;
  };
}>
DrawerRootProps
React.ReactNode
ModalBaseOverlayProps
ModalBaseCloseButtonProps
HTMLDivElement
DrawerRootStylesNames
DrawerRootCssVariables