Modal
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
Present a focused modal workflow.
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 prop | Explanation |
|---|---|
Button.onClick | Local click handler; replace demo logic with an explicit business action. |
Modal.opened | Whether the controlled region is open. |
Modal.onClose | Request to close; update the host's open state. |
Modal.title | Heading content for this component. |
Modal.closeButtonProps | Native 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
opened/onClose are controlled by the host. Keep the native Portal enabled: the iframe already isolates the preview. Test placement, Escape and focus restoration in the consuming app.
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 modal</M.Button><M.Modal opened={open} onClose={() => setOpen(false)} title="Welcome" closeButtonProps={{ "aria-label": "Close modal / 关闭弹窗" }}>{content}</M.Modal></>;
}
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
Center modal vertically
Remove header
To remove the header, set withCloseButton={false}:
Change size
You can change the modal width by setting the size prop to a predefined size or any valid width, for example, 55% or 50rem.
The Modal width cannot exceed 100vw.
Size auto
Modal with size="auto" will have width that fits its content:
Fullscreen
A fullscreen modal will take the entire screen. It is usually better to change the transition to fade
when the fullScreen prop is set:
To switch Modal to fullscreen on devices with small screens only, use the use-media-query hook.
The size prop is ignored if the fullScreen prop is set:
Customize overlay
Modal uses the Overlay component. You can set any props that Overlay
supports with overlayProps:
Modal with scroll
Usage with ScrollArea
Change offsets
Use xOffset/yOffset to configure the horizontal/vertical content offsets:
Change transitions
Modal 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 modal is closed:
Initial focus
Modal 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 modal 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 modal will focus the first focusable element inside it, which is usually the close button.
Control behavior
The following props can be used to control Modal 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 the modalcloseOnEscape– determines whether the modal should be closed when theEscapekey is pressedcloseOnClickOutside– determines whether the modal should be closed when the user clicks on the overlayreturnFocus– determines whether focus should be returned to the element that was focused before the modal was opened
react-remove-scroll settings
Modal uses the react-remove-scroll
package to lock scroll. You can pass props down to the RemoveScroll component
with removeScrollProps:
import { Modal } from '@mantine/core';
function Demo() {
return (
<Modal
removeScrollProps={{ allowPinchZoom: true }}
opened
onClose={() => {}}
/>
);
}
Change close icon
Use closeButtonProps to customize the close button:
Compound components
You can use the following compound components to have full control over the Modal rendering:
Modal.Root– context providerModal.Overlay– render OverlayModal.Content– main modal element, should include all modal contentModal.Header– sticky header, usually containsModal.TitleandModal.CloseButtonModal.Title–h2element, thearia-labelledbyofModal.Contentis pointing to this element, usually rendered insideModal.HeaderModal.CloseButton– close button, usually rendered insideModal.HeaderModal.Body– a place for main content, thearia-describedbyofModal.Contentis pointing to this element
Modal.Stack
Use the Modal.Stack component to render multiple modals at the same time.
Modal.Stack keeps track of opened modals, manages z-index values, focus trapping,
and closeOnEscape behavior. Modal.Stack is designed to be used with the useModalsStack hook.
Differences from using multiple Modal components:
Modal.Stackmanages z-index values – modals that are opened later will always have a higher z-index value regardless of their order in the DOMModal.Stackdisables focus trap andEscapekey handling for all modals except the one that is currently opened- Modals that are not currently opened are present in the DOM but are hidden with
opacity: 0andpointer-events: none - Only one overlay is rendered at a time
Note that Modal.Stack can only be used with the Modal component. Components built with Modal.Root
and other compound components are not compatible with Modal.Stack.
useModalsStack hook
The useModalsStack hook provides an easy way to control multiple modals at the same time.
It accepts an array of unique modal IDs and returns an object with the following properties:
interface UseModalsStackReturnType<T extends string> {
// Current opened state of each modal
state: Record<T, boolean>;
// Opens modal with the given id
open: (id: T) => void;
// Closes modal with the given id
close: (id: T) => void;
// Toggles modal with the given id
toggle: (id: T) => void;
// Closes all modals within the stack
closeAll: () => void;
// Returns props for modal with the given id
register: (id: T) => {
opened: boolean;
onClose: () => void;
stackId: T;
};
}
Example of using useModalsStack with the Modal component:
import { Modal, useModalsStack } from '@mantine/core';
function Demo() {
const stack = useModalsStack(['first', 'second']);
return (
<>
<Modal {...stack.register('first')}>First</Modal>
<Modal {...stack.register('second')}>Second</Modal>
<Button onClick={() => stack.open('first')}>Open first</Button>
</>
);
}
Fixed elements offset
The Modal component uses the 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
The Modal component follows WAI-ARIA recommendations on accessibility.
Set the title prop to make the component accessible, which will add aria-labelledby to the content element:
import { Modal } from '@mantine/core';
function Demo() {
return <Modal title="Modal label" opened onClose={() => {}} />;
}
To set the close button's aria-label, use closeButtonProps:
import { Modal } from '@mantine/core';
function Demo() {
return (
<Modal
closeButtonProps={{ 'aria-label': 'Close modal' }}
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.
Modal(_props)
export type ModalStylesNames = ModalRootStylesNames;
export type ModalCssVariables = ModalRootCssVariables;
export interface ModalProps extends ModalRootProps {
__staticSelector?: string;
/** Modal title */
title?: React.ReactNode;
/** If set, the overlay is rendered @default true */
withOverlay?: boolean;
/** Props passed down to the `Overlay` component, use to configure opacity, `background-color`, styles and other properties */
overlayProps?: ModalBaseOverlayProps;
/** Modal content */
children?: React.ReactNode;
/** If set, the close button is rendered @default true */
withCloseButton?: boolean;
/** Props passed down to the close button */
closeButtonProps?: ModalBaseCloseButtonProps;
/** Id of the modal in the `Modal.Stack` */
stackId?: string;
}
export type ModalFactory = Factory<{
props: ModalProps;
ref: HTMLDivElement;
stylesNames: ModalStylesNames;
vars: ModalCssVariables;
staticComponents: {
Root: typeof ModalRoot;
Overlay: typeof ModalOverlay;
Content: typeof ModalContent;
Body: typeof ModalBody;
Header: typeof ModalHeader;
Title: typeof ModalTitle;
CloseButton: typeof ModalCloseButton;
Stack: typeof ModalStack;
};
}>;
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: ModalProps;
ref: HTMLDivElement;
stylesNames: ModalStylesNames;
vars: ModalCssVariables;
staticComponents: {
Root: typeof ModalRoot;
Overlay: typeof ModalOverlay;
Content: typeof ModalContent;
Body: typeof ModalBody;
Header: typeof ModalHeader;
Title: typeof ModalTitle;
CloseButton: typeof ModalCloseButton;
Stack: typeof ModalStack;
};
}>
ModalRootProps
React.ReactNode
ModalBaseOverlayProps
ModalBaseCloseButtonProps
HTMLDivElement
ModalRootStylesNames
ModalRootCssVariables