Blueprint

Modal

Modal is part of a collection of components, also including Dialog, Sheet and Drawer, that overlay content on top of a full-page view and often block the UI below. A Modal presents content, tasks, or actions that require exclusive user focus.

Design guidance

When and how to use this

Use a Modal where a user needs to complete a task or take an action that requires the user's full attention. For example, if the user needs to fill out a brief form to complete an action, you might consider a Modal, especially if it would be inappropriate to insert the form into the document flow.

When to consider something else

If the task or action is too complex or lengthy to comfortably fit in a Modal you can use a Drawer instead. A Drawer would also be more appropriate for showing read-only details about an item in a list.

Use a Dialog instead of a Modal if the user just needs to give a simple confirmation, especially following the invocation of a destructive action.


Figma

Drag in a Modal from the Modals v2 library in the Assets pane in your Figma file. You will need to separately drag in a ModalOverlay to go behind the Modal in your design. We provide 3 size variants that correspond with those found in our React Modal component, with Medium as the default. Note that after choosing the appropriate size variant for your use case, you will want to detach the component instance in order to work with the content in the Modal.

React


import { Modal } from '@hover/blueprint';

Render the Modal component itself unconditionally using the isOpen and onClose props to control its open state. The useDisclosure hook is purpose-built to manage the open state of overlays.

Initial Focus

By default, the first focusable element will receive focus when the Modal is opened. Pass initialFocusRef to focus on a particular element instead.

live

() => {
const { isOpen, onOpen, onClose } = useDisclosure();
return (
<>
<Modal
footer={
<>
<Button fill="outline" size="large">
Charge Lasers
</Button>
<Button size="large">Fire Lasers</Button>
</>
}
header="Spectacular Header"
isOpen={isOpen}
onClose={onClose}
>
Lorem ipsum dolor sit amet consectetur adipiscing elit. Amet consectetur
adipiscing elit quisque faucibus ex sapien. Quisque faucibus ex sapien
vitae pellentesque sem placerat. Vitae pellentesque sem placerat in id
cursus mi.
</Modal>
<Button iconBefore={iMaximize} onClick={onOpen} shape="box">
Open
</Button>
</>
);
};


PropDescription
sizeSets a specific size for the Modal. Valid values are small, medium, large, full or auto. See below for more information on sizing.
headerSets the heading content. The value can be a simple string, in which case it is rendered as the appropriate Heading style. A JSX fragment can also be provided.
footerSets the footer content. When provided, footer content is wrapped in an HStack by default with the appropriate spacing. If the footer content is wrapped in a layout container (Box, Stack, etc.), it will be rendered as the footer element.
isClosableDefaults to true.

Scrollable Content

By default, content will expand the modal to fill screen. When displaying long-form content in a Modal, you likely want to restrict the height of the scrollable container. Pass maxContentHeight to control the maximum height of the scroll container.

live

() => {
const { isOpen, onOpen, onClose } = useDisclosure();
return (
<>
<Modal
maxContentHeight="40vh"
header="Terms & Privacy"
size="small"
isOpen={isOpen}
onClose={onClose}
footer={
<>
<Button size="large" onClick={onClose}>
Accept
</Button>
<Button fill="minimal" size="large" onClick={onClose}>
Cancel
</Button>
</>
}
>
<Heading size={300}>Terms of Use</Heading>
<LoremIpsum generate={{ p: 2 }} />
<Heading size={300}>Privacy Policy</Heading>
<LoremIpsum generate={{ p: 3, sentences: 5 }} />
</Modal>
<Button iconBefore={hUserBusiness} onClick={onOpen} shape="box">
Terms & Privacy
</Button>
</>
);
};

Size

Responsive Sizing

The default size will select a size automatically using media queries, so setting an explicit size is usually only necessary to specify auto or full.

live

() => {
const { isOpen, onOpen, onClose } = useDisclosure();
const [size, setSize] = useState(undefined);
const select = (
<Select
onChange={event => setSize(event.target.value)}
size="small"
value={size ?? 'default'}
width="auto"
>
{['full', 'small', 'medium', 'default', 'large', 'auto'].map(size => (
<option key={size}>{size}</option>
))}
</Select>
);
return (
<>
<Modal
footer={select}
header="Header"
isOpen={isOpen}
onClose={onClose}
size={size}
>
<Image src="/images/kitten--1920-1080.jpg" />
</Modal>
<HStack>
<Button iconBefore={iMaximize} onClick={onOpen} shape="box">
Open
</Button>
{select}
</HStack>
</>
);
};

Full

Expand the Modal to fill the viewport in both dimensions.

Auto

Size the Modal to fit its content.

This size is useful for images and other media that have explicit dimensions or if you want to control the size of the Modal manually by specifying width and/or height on the children.

Bootstrap

To use the Bootstrap Modal you must have the Bootstrap JavaScript bundle installed. You do not need to initialize this component with your own JS. It should just work!

Here is an example of what a Bootstrap Modal looks like (we have overridden a couple of things so you can see it without having to click a trigger to open it). By default, you will get the size and typography shown. We offer 3 size variants aligned to the Figma components. The class .modal-md is the same as the default, as shown here. You can use .modal-lg or .modal-sm to get those size variants. See Bootstrap's docs for Modal for more options and classes you can use if the basics shown here don't cover your use case.

live

<div class="docs-example">
<div class="modal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Modal title</h5>
<button
type="button"
class="btn-close"
data-bs-dismiss="modal"
aria-label="Close"
></button>
</div>
<div class="modal-body">
<p>
Lorem ipsum dolor sit amet,
<a href="#">consectetur adipiscing elit</a>. Quisque arcu elit,
viverra tincidunt ullamcorper id, fermentum vel dui. Proin non risus
urna. Vestibulum mauris ex, scelerisque at volutpat eu, posuere in
purus. Suspendisse hendrerit enim dui, ut tincidunt ipsum volutpat
varius. Suspendisse consequat fermentum neque, vitae faucibus orci
posuere vel.
</p>
</div>
<div class="modal-footer">
<button
type="button"
class="btn btn-outline-primary"
data-bs-dismiss="modal"
>
Cancel
</button>
<button type="button" class="btn btn-primary">Save</button>
</div>
</div>
</div>
</div>
</div>


ClassDescription
.modal-sm, .modal-lgApply to your <div class="modal"> wrapper to set a non-default size for your Modal.