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 togglearia-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-labelledbyattribute 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> ); }