A window overlaid on either the primary window or another dialog window, rendering the content underneath inert.
Supports modal and non-modal modes.
Focus is automatically trapped when modal.
Can be controlled or uncontrolled.
Manages screen reader announcements with Title
and Description
components.
Esc closes the component automatically.
Install the component from your command line.
npm install @radix-ui/react-dialog
Import all parts and piece them together.
import * as Dialog from '@radix-ui/react-dialog';
export default () => (
<Dialog.Root>
<Dialog.Trigger />
<Dialog.Portal>
<Dialog.Overlay />
<Dialog.Content>
<Dialog.Title />
<Dialog.Description />
<Dialog.Close />
</Dialog.Content>
</Dialog.Portal>
</Dialog.Root>
);
Contains all the parts of a dialog.
The button that opens the dialog.
When used, portals your overlay and content parts into the body
.
A layer that covers the inert portion of the view when the dialog is open.
Contains content to be rendered in the open dialog.
The button that closes the dialog.
An accessible title to be announced when the dialog is opened.
If you want to hide the title, wrap it inside our Visually Hidden utility like this <VisuallyHidden asChild>
.
An optional accessible description to be announced when the dialog is opened.
If you want to hide the description, wrap it inside our Visually Hidden utility like this <VisuallyHidden asChild>
. If you want to remove the description entirely, remove this part and pass aria-describedby={undefined}
to Dialog.Content
.
Use the controlled props to programmatically close the Dialog after an async operation has completed.
import React from 'react';
import * as Dialog from '@radix-ui/react-dialog';
const wait = () => new Promise((resolve) => setTimeout(resolve, 1000));
export default () => {
const [open, setOpen] = React.useState(false);
return (
<Dialog.Root open={open} onOpenChange={setOpen}>
<Dialog.Trigger>Open</Dialog.Trigger>
<Dialog.Portal>
<Dialog.Overlay />
<Dialog.Content>
<form
onSubmit={(event) => {
wait().then(() => setOpen(false));
event.preventDefault();
}}
>
{/** some inputs */}
<button type="submit">Submit</button>
</form>
</Dialog.Content>
</Dialog.Portal>
</Dialog.Root>
);
};
Move the content inside the overlay to render a dialog with overflow.
// index.jsx
import * as Dialog from '@radix-ui/react-dialog';
import './styles.css';
export default () => {
return (
<Dialog.Root>
<Dialog.Trigger />
<Dialog.Portal>
<Dialog.Overlay className="DialogOverlay">
<Dialog.Content className="DialogContent">...</Dialog.Content>
</Dialog.Overlay>
</Dialog.Portal>
</Dialog.Root>
);
};
/* styles.css */
.DialogOverlay {
background: rgba(0 0 0 / 0.5);
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
display: grid;
place-items: center;
overflow-y: auto;
}
.DialogContent {
min-width: 300px;
background: white;
padding: 30px;
border-radius: 4px;
}
Customise the element that your dialog portals into.
import React from 'react';
import * as Dialog from '@radix-ui/react-dialog';
export default () => {
const [container, setContainer] = React.useState(null);
return (
<div>
<Dialog.Root>
<Dialog.Trigger />
<Dialog.Portal container={container}>
<Dialog.Overlay />
<Dialog.Content>...</Dialog.Content>
</Dialog.Portal>
</Dialog.Root>
<div ref={setContainer} />
</div>
);
};
Adheres to the Dialog WAI-ARIA design pattern.
Create your own API by abstracting the primitive parts into your own component.
This example abstracts the Dialog.Overlay
and Dialog.Close
parts.
import { Dialog, DialogTrigger, DialogContent } from './your-dialog';
export default () => (
<Dialog>
<DialogTrigger>Dialog trigger</DialogTrigger>
<DialogContent>Dialog Content</DialogContent>
</Dialog>
);
// your-dialog.jsx
import React from 'react';
import * as DialogPrimitive from '@radix-ui/react-dialog';
import { Cross1Icon } from '@radix-ui/react-icons';
export const DialogContent = React.forwardRef(
({ children, ...props }, forwardedRef) => (
<DialogPrimitive.Portal>
<DialogPrimitive.Overlay />
<DialogPrimitive.Content {...props} ref={forwardedRef}>
{children}
<DialogPrimitive.Close aria-label="Close">
<Cross1Icon />
</DialogPrimitive.Close>
</DialogPrimitive.Content>
</DialogPrimitive.Portal>
)
);
export const Dialog = DialogPrimitive.Root;
export const DialogTrigger = DialogPrimitive.Trigger;