Modal

Modals inform users about a task and can contain critical information, require decisions, or involve multiple tasks.

() => {
const [open, setOpen] = React.useState(false);
const unfilteredOptions = [
{
id: 1,
firstName: 'Joe',
lastName: 'Bob',
subTitle: 'Some Subtitle',
avatar: 'https://placehold.it/50',
type: 'People',
disabled: true,
disabledText: "I'm disabled",
},
{
id: 2,
firstName: 'Jill',
lastName: 'Jackson',
subTitle: 'Some Subtitle',
type: 'People',
},
{
id: 3,
firstName: 'Frank',
lastName: 'Sinatra',
subTitle: 'Some Subtitle',
type: 'People',
},
{
id: 4,
firstName: 'Billy',
lastName: 'Jean',
subTitle: 'Some Subtitle',
avatar: 'https://placehold.it/50',
type: 'People',
},
{
id: 5,
firstName: 'Meryl',
lastName: 'Streep',
subTitle: 'Some Subtitle',
avatar: 'https://placehold.it/50',
type: 'People',
},
{
id: 6,
firstName: 'Bob',
lastName: 'Saget',
subTitle: 'Some Subtitle',
avatar: 'https://placehold.it/50',
type: 'People',
},
{
id: 7,
firstName: 'Zoe',
lastName: 'Deschanel',
subTitle: 'Some Subtitle',
avatar: 'https://placehold.it/50',
type: 'People',
},
{
id: 8,
firstName: 'Will',
lastName: 'Ferrell',
subTitle: 'Some Subtitle',
avatar: 'https://placehold.it/50',
type: 'People',
},
{
id: 9,
firstName: 'John',
lastName: 'Candy',
subTitle: 'Some Subtitle',
avatar: 'https://placehold.it/50',
type: 'People',
},
{
id: 10,
firstName: 'Jane',
lastName: 'Merry',
subTitle: 'Some Subtitle',
avatar: 'https://placehold.it/50',
type: 'People',
},
{
id: 11,
firstName: 'Jill',
lastName: 'Ferrell',
subTitle: 'Some Subtitle',
avatar: 'https://placehold.it/50',
type: 'People',
},
{
id: 12,
firstName: 'Jerry',
lastName: 'Candy',
subTitle: 'Some Subtitle',
avatar: 'https://placehold.it/50',
type: 'People',
},
];
const [loading, setLoading] = React.useState(false);
const [searchText, setSearchText] = React.useState('');
const debouncedText = useDebouncedValue(searchText);
const [options, setOptions] = React.useState([]);
React.useEffect(() => {
if (searchText) {
setLoading(true);
const timeoutId = setTimeout(() => {
setLoading(false);
setOptions(
unfilteredOptions.filter((option) =>
new RegExp(searchText, 'ig').test(
`${option.firstName} ${option.lastName}`,
),
),
);
}, 500 + Math.floor(Math.random() * 2000));
return () => {
clearTimeout(timeoutId);
setLoading(false);
};
} else {
setOptions([]);
}
}, [debouncedText]);
return (
<>
<Button onClick={() => setOpen(true)}>Open Search Modal</Button>
<Modal
id="simple-Modal"
title="Title"
open={open}
backButtonProps={{ className: 'back-button-classname' }}
onClose={() => setOpen(false)}
>
<Search
helperText="Enter a name to search"
id="people-single-search"
multiple={false}
noOptionsText="We couldn't find anyone who matched your search"
loading={loading}
onChange={console.log}
onInputChange={(e) => setSearchText(e.target.value)}
options={options}
placeholder="Search"
variant="large"
type="single"
renderOption={(props, option) => (
<SearchOptionCard
{...props}
avatarUrl={option.avatar}
showAvatar
title={`${option.firstName} ${option.lastName}`}
subTitle={option.subTitle}
type={option.type}
/>
)}
/>
</Modal>
</>
);
};

Props

PropTypeDefaultDescription
actionsButton[]The Modal action button(s)
backTextstringBackThe text for the Modal back button
backDataTestIdstringThe data-testid that will be assigned to the Modal back button
backButtonPropsPartial<ButtonProps>Props for the back button
childrennodeModal children, usually the included sub-components.
idstringThe id(s) of the element(s) that describe/label the Modal.
onBackfunctionCallback when the back button is clicked
onClosefunctionCallback when an action is taken to close the Modal
open*boolIf true, the Modal is open.
titlestringTitle of the Modal
titleTypographyPropsPartial<TypographyProps>Props for the Title typography
fullScreenbooleanDisplay fullScreen Modal
disableCloseButtonbooleanDisables the interaction with the close button on the modal title when passed true
disableBackTextbooleanDisables the interaction with the Back text on the modal title when passed true
backTextAutoFocusbooleanBack text will be auto-focused when true is passed.

The ref is forwarded to the root element.

Examples

Basic

() => {
const [open, setOpen] = React.useState(false);
const [page, setPage] = React.useState(1);
const handleOpen = () => {
setOpen(true);
};
const handleClose = (value) => {
setOpen(false);
setPage(1);
};
return (
<>
<Button color="primary" onClick={handleOpen}>
Open Basic Modal
</Button>
<Modal
actions={
<>
<Button
onClick={() => {
if (page === 1) setPage(2);
else handleClose();
}}
>
{page === 1 ? 'Next' : 'Save'}
</Button>
<Button onClick={handleClose} color="secondary">
Cancel
</Button>
</>
}
backText="Back"
id="simple-Modal"
onBack={page > 1 ? () => setPage(1) : null}
onClose={handleClose}
open={open}
title="Title"
>
<div>
{Array(page > 1 ? 1 : 40)
.fill('')
.map((_, i) => (
<Typography key={i}>Some simple Modal page {page}</Typography>
))}
</div>
</Modal>
</>
);
};

Collapse

() => {
const [open, setOpen] = React.useState(false);
const [page, setPage] = React.useState(1);
const [collapse, setCollapse] = React.useState(false);
const handleOpen = () => {
setOpen(true);
};
const handleClose = (value) => {
setOpen(false);
};
return (
<>
<Button color="primary" onClick={handleOpen}>
Open Collapse Modal
</Button>
<Modal
actions={
<>
<Button
onClick={() => {
setCollapse((collapse) => !collapse);
}}
>
{collapse ? 'Show Less' : 'Show More'}
</Button>
<Button onClick={handleClose} color="secondary">
Cancel
</Button>
</>
}
id="collapse-Modal"
onClose={handleClose}
open={open}
title="Title"
>
{Array(10)
.fill('')
.map((_, i) => (
<Typography key={i}>Some simple Modal content</Typography>
))}
<Collapse in={collapse} timeout={1000}>
{Array(10)
.fill('')
.map((_, i) => (
<Typography key={i}>More simple Modal content</Typography>
))}
</Collapse>
</Modal>
</>
);
};

Full Screen

() => {
const [open, setOpen] = React.useState(false);
const [page, setPage] = React.useState(0);
const isMobile = useMediaQuery('(max-width: 480px)');
const handleOpen = () => {
setOpen(true);
};
const handleClose = (value) => {
setOpen(false);
setPage(0);
};
return (
<>
<Button color="primary" onClick={handleOpen}>
Open Full Screen Modal
</Button>
<Modal
actions={
<>
<Button
data-testid="next-button"
size="extraLarge"
onClick={() => {
if (page === 0) setPage(1);
else handleClose();
}}
>
{page === 0 ? 'Next' : 'Save'}
</Button>
</>
}
backText="Back"
id="fullScreen-Modal"
onBack={page > 0 ? () => setPage(0) : null}
onClose={handleClose}
open={open}
fullScreen
title={isMobile ? 'Recognize' : ''}
>
<div>
<Stepper
steps={[
{ label: 'Who', id: 0 },
{ label: 'Recognize', id: 1 },
{ label: 'Message', id: 2 },
{ label: 'Review & Submit', id: 3 },
]}
activeStep={page}
onStepClick={(step) => setPage(step.id)}
/>
<Typography variant="h1" sx={{ marginTop: '48px' }}>
{page === 0
? 'Who are you recognizing?'
: 'Personalize your message'}
</Typography>
<div>
{Array(page > 0 ? 1 : 40)
.fill('')
.map((_, i) => (
<Typography key={i}>
Some full screen modal content page {page}
</Typography>
))}
</div>
</div>
</Modal>
</>
);
};