Skip to main content

Dialog

Creates a dialog modal that fills the whole screen and has a black opacity overlay.

Accessibility

Dialogs, by definition, trap focus. This means that if a user presses Tab or Shift+Tab while their keyboard focus is in the dialog, their focus should stay in and cycle through the dialog’s content. Focus shouldn’t return to the underlying page until the user presses the Esc key, presses an explicit “Cancel” or “Close” button in the dialog, or performs another action that closes the dialog.

Expected markup:

  • Dialog has role="dialog"
  • When the dialog is open, everything behind it has HTML attribute aria-hidden="true", so assistive technology won't read out the underlying page. The best way to do this is to give the dialog and the page separate wrapper elements and toggle aria-hidden="true"/aria-hidden="false" on the main page's wrapper depending on the dialog is open.
  • Dialog contains an HTML heading
  • Dialog has an aria-labelledby attribute whose value is the id of the dialog’s heading

Anatomy

Dialog has buttons flat normal as a default. Other types or variations are possible and are defined case by case by design.

Notes

The component uses @radix-ui/react-dialog under the hood.

Example

Alert

Result
Loading...
Live Editor
function ExampleAlert() {
    const [ visible, setVisible ] = React.useState(false);
    const show = () => setVisible(true);
    const hide = () => setVisible(false);
    return (
        <div>
            <Button
                type="button"
                typeStyle="outlined"
                variationStyle="normal"
                onClick={show}
            >
                Show dialog
            </Button>
            <Dialog
                open={visible}
                onClose={hide}
            >
                <DialogTitle>
                    Do you want to do that?
                </DialogTitle>
                <DialogContent>
                    Lorem ipsum dolor sit, amet consectetur adipisicing elit. Nobis, ullam.
                </DialogContent>
                <DialogActions>
                    <Button
                        typeStyle="flat"
                        variationStyle="brand"
                        onClick={hide}
                    >
                        Confirm
                    </Button>
                    <Button
                        typeStyle="flat"
                        variationStyle="normal"
                        onClick={hide}
                    >
                        Cancel
                    </Button>
                </DialogActions>
            </Dialog>
        </div>
    );
}

Full-screen

Result
Loading...
Live Editor
function ExampleFullscreen() {
    const [ visible, setVisible ] = React.useState(false);
    const show = () => setVisible(true);
    const hide = () => setVisible(false);
    return (
        <div>
            <Button
                type="button"
                typeStyle="outlined"
                variationStyle="normal"
                onClick={show}
            >
                Show dialog
            </Button>
            <Dialog
                open={visible}
                onClose={hide}
                fullScreen
            >
                <DialogTitle>
                    Full-screen dialog
                </DialogTitle>
                <DialogContent>
                    Lorem ipsum dolor sit amet consectetur adipisicing elit. Totam fugiat sit reiciendis
                    perspiciatis iure! Ab voluptate, molestias ratione nam commodi reprehenderit sapiente
                    recusandae harum sunt repudiandae! Qui, libero provident! Perferendis cupiditate qui sit!
                    Beatae neque inventore vel quisquam pariatur facilis.
                </DialogContent>
                <DialogActions>
                    <Button
                        typeStyle="flat"
                        variationStyle="normal"
                        onClick={hide}
                    >
                        Close
                    </Button>
                </DialogActions>
            </Dialog>
        </div>
    );
}

Optional sizes

Result
Loading...
Live Editor
function ExampleOptionalSizes() {
    const [ visible, setVisible ] = React.useState(false);
    const [ maxWidth, setMaxWidth ] = React.useState('sm');
    const [ fullWidth, setFullWidth ] = React.useState(true);
    const show = () => setVisible(true);
    const hide = () => setVisible(false);
    const handleMaxWidthChange = (event) => {
        setMaxWidth(event.target.value);
    };
    const handleFullWidthChange = (event) => {
        setFullWidth(event.target.checked);
    }
    return (
        <div>
            <Button
                type="button"
                typeStyle="outlined"
                variationStyle="normal"
                onClick={show}
            >
                Show dialog
            </Button>
            <Dialog
                open={visible}
                onClose={hide}
                fullWidth={fullWidth}
                maxWidth={maxWidth}
            >
                <DialogTitle>
                    Do you want to do that?
                </DialogTitle>
                <DialogContent>
                    <div style={{ display: 'flex', flexDirection: 'column', margin: 'auto', width: 'fit-content' }}>
                        <div style={{ minWidth: '160px' }}>
                            <FormField id="demo-optional-sizes-max-width" labelText="maxWidth">
                                <Select value={maxWidth} onChange={handleMaxWidthChange}>
                                    <option value={false}>false</option>
                                    <option value="xs">xs</option>
                                    <option value="sm">sm</option>
                                    <option value="md">md</option>
                                    <option value="lg">lg</option>
                                </Select>
                            </FormField>
                            <div>
                                <Toggle id="demo-optional-sizes-full-width" checked={fullWidth} onChange={handleFullWidthChange} />
                                <label htmlFor="demo-optional-sizes-full-width">
                                    fullWidth
                                </label>
                            </div>
                        </div>
                    </div>
                </DialogContent>
                <DialogActions>
                    <Button
                        typeStyle="flat"
                        variationStyle="brand"
                        onClick={hide}
                    >
                        Confirm
                    </Button>
                    <Button
                        typeStyle="flat"
                        variationStyle="normal"
                        onClick={hide}
                    >
                        Cancel
                    </Button>
                </DialogActions>
            </Dialog>
        </div>
    );
}

Scrolling long content

Result
Loading...
Live Editor
function ExampleScrollingLongContent() {
    const [ visible, setVisible ] = React.useState(false);
    const show = () => setVisible(true);
    const hide = () => setVisible(false);
    return (
        <div>
            <Button
                type="button"
                typeStyle="outlined"
                variationStyle="normal"
                onClick={show}
            >
                Show dialog
            </Button>
            <Dialog
                open={visible}
                onClose={hide}
            >
                <DialogTitle>
                    Long Scrollable Text
                </DialogTitle>
                <DialogContent>
                    {new Array(50).fill('').map(
                        () => `Lorem ipsum dolor sit amet consectetur
adipisicing elit. Inventore, eum quod culpa aut assumenda tempora debitis
facilis neque vel at minus voluptatum recusandae corporis quis excepturi,
architecto consectetur totam velit a, quos dolorem odit numquam. Corrupti
nobis odio corporis provident, nemo asperiores sit? Nesciunt nemo ratione
obcaecati ex distinctio molestias vel, non quibusdam! Omnis esse iusto
necessitatibus delectus cupiditate repudiandae facere ad officia. Ad
eveniet quaerat incidunt? Cumque earum velit magnam laboriosam, fugiat
odio quis odit tempora quibusdam consectetur accusantium perspiciatis,
ducimus eius expedita sit non incidunt quaerat quasi debitis deleniti ut
eveniet! Enim omnis id a? Quis perspiciatis architecto, esse laboriosam
porro accusamus modi unde molestias expedita. Nam totam labore harum aut
molestiae cupiditate excepturi. Ut sint officia similique!`
                    ).join('\n')}
                </DialogContent>
                <DialogActions>
                    <Button
                        typeStyle="flat"
                        variationStyle="normal"
                        onClick={hide}
                    >
                        Close
                    </Button>
                </DialogActions>
            </Dialog>
        </div>
    );
}

Stacked

Result
Loading...
Live Editor
function ExampleNesting() {
    const dialogCount = 3;
    const [ visibleDialogs, setVisibleDialogs ] = React.useState([]);

    const isOpen = (index) => {
        return visibleDialogs.includes(index);
    }

    const open = (index) => {
        setVisibleDialogs((visibleDialogs) => {
            return [ ...visibleDialogs, index ];
        });
    }
    const close = (index) => {
        setVisibleDialogs((visibleDialogs) => {
            return visibleDialogs.filter((dialogIndex) => dialogIndex !== index)
        });
    }

    return (
        <Fragment>
            <Button
                type="button"
                typeStyle="outlined"
                variationStyle="normal"
                onClick={() => {
                    open(0);
                }}
            >
                Open dialog 1
            </Button>
            {new Array(dialogCount).fill('').map((_, index) => {
                const next = index === dialogCount - 1
                    ? null
                    : index + 1;

                return (
                    <Dialog
                        key={index}
                        open={isOpen(index)}
                        onClose={() => {
                            close(index)
                        }}
                    >
                        <DialogTitle>
                            Dialog #{index + 1}
                        </DialogTitle>
                        <DialogContent>
                            {next !== null &&
                                `Here you can open dialog ${next + 1} or close the current dialog.`}
                            {next === null && 'Last dialog'}
                        </DialogContent>
                        <DialogActions>
                            {next !== null && (
                                <Button
                                    type="button"
                                    typeStyle="flat"
                                    variationStyle="brand"
                                    onClick={() => {
                                        open(next);
                                    }}
                                >
                                    Open dialog #{next + 1}
                                </Button>
                            )}
                            <Button
                                typeStyle="flat"
                                variationStyle="normal"
                                onClick={() => {
                                    close(index);
                                }}
                            >
                                Close
                            </Button>
                        </DialogActions>
                    </Dialog>
                )
            })}
        </Fragment>
    );
}