Modals are dialogs displayed over inert content that allow users to complete a singular, focused task without leaving the page.
Modals are used occasionally in our application, when the user is required to make choices before they can proceed. Here are some examples:
Confirm action. For example, it should be easy to delete campaigns or emails, but we need to carefully check that it's not a misclick. A modal demands a decision before deleting.
In context, but focused. Some tasks need UI which doesn't fit in-line, but is not big enough to have its own page. A modal is a good choice for focusing here. Examples include adding a new email, or setting the split for an A/B test.
Feature moments. Exporting data or starting a campaign are small API actions that we want to celebrate with animation and flair. A modal is a great way to do this, when used sparingly.
Some guidelines for using modals:
Make the next step clear. Even if it's just a "Got it!" button at the bottom, there needs to be an obvious action for the user. If not, why is it a modal?
Consistency through reuse. We have a delete-button modal in our application, which should be used instead of a custom modal when deleting something. Look for a modal you can reuse, or at least use the same design.
Consider popups. Modals interrupt the UI flow, make it hard to multi-task, and aren't routable. If the interaction doesn't fit one of the above three categories, consider a click button popup instead.
A Modal consists of several components:
Modal
ModalHeader
title prop.ModalTitle
ModalBody
ModalFooter
ModalInset
The components can be imported via:
At it's simplest, a Modal will require:
isOpen prop
onClose prop
isOpen state accordingly.title prop
ModalBody
ModalBody is required for the body to handle overflow scrolling correctly.ModalFooter, with buttons or other actions
The modal component accepts a few callbacks related to its open state:
onClose - this is called when the modal should be closed (for example, when the "close" "X" button is clicked)
isOpen state to false - otherwise, the modal will stay openonOpen - this is called when the modal first renders into the DOM
isOpen state is controlled from outside the modal, this
callback wouldn't be used to set isOpen. Instead, this can be used to
react to a state change from closed to opened if isOpen is controlled
by another parent component in the apponCloseComplete - when a modal closes, it will animate out, and unmount after
the animation. This is called when the modal fully unmounts, after the animation is finishedFor example, open devtools and see the console logs on the below modal:
By default, modals are dismissable and will close when:
Depending on the use case, it may be necessary to disable one or more of these behaviors. Each of the dismissals can be controlled via a prop:
shouldShowCloseButton
false, the close button in the header won't be rendered.shouldCloseOnOverlayClick
false, clicking the overlay won't close the modal.shouldCloseOnEscapePress
false, pressing the "Escape" key won't close the modal.Additionally, there is an isDismissable prop, which is a shortcut for disabling all of the above.
Note: The individual props, if set, will still take precedence over the isDismissable setting.
If you have a small amount of content, you can use the size prop to make the modal smaller.
A modal will stretch vertically to accommodate its content, up to a certain maximum height.
After that, the ModalBody will become scrollable.
Try opening the below modal and resizing your browser to make it shorter:
Alternatively, it's possible to set the scrolling behavior so that the entire viewport scrolls instead.
This is done by setting the shouldScrollInViewport prop to true:
By default ModalBody contains padding to keep the content from the edges of the modal.
In some cases, it may be necessary for the content to stretch all the way to the edges -
for example, when showing a full-width image or table.
To make this possible, the ModalInset component can be used:
In some cases, we want to make a modal more graphic and include an image, content with a visual background, or more. The split modal variant splits the main modal content into two halves vertically, and renders the header, close button, body, and footer on the right side, and leaves the left side free for any visual content. The left half goes from top to bottom and has no padding.
To make this possible, use ModalSplit as a child of Modal. Placing ModalSplit before
ModalBody will place the graphic content on the left, and placing it after will place the graphic
content on the right.
To make modal's accessible, the component contains the following features:
initialFocusIndex propPlumaModal extends BoxDefault:125
The duration (in ms) for the modal animation.
By default, the modal will focus the first focusable element. You can override this by setting the index of the focusable element you want to focus instead.
A shortcut to set shouldShowCloseButton, shouldCloseOnOverlayClick, and shouldCloseOnEscapePress to false.
The other prop values still take precedence, if set, even when isDismissable is true.
Whether the modal is open.
Called when the modal is requesting to be closed. For example, when clicking the close button, clicking the overlay, or pressing the Escape key.
Called when the modal finishes closing (after the close animation finishes).
Called when the modal is opened.
Whether onClose should be called when the Escape key is pressed.
Whether onClose should be called when the overlay is clicked.
When the modal's content is long and causing overflows, this controls whether the whole modal should scroll inside the viewport, rather than the modal's body being the scroll container.
Whether a close button should be displayed in the modal.
The size of the modal.
A special prop containing all the other modal props for use with the ModalsManager.
The title of the modal.
If none is provided, the default ModalHeader will not render.