Modal
A design structure to organize and hide content, so as not to overwhelm the user.
Modals provide an opportunity to display content, focused actions or alerts while maintaining the context of an existing view. This limits workflow interruptions and allows for focused communication and user interactions. There are two types of modals in Base – default and alert. Each modal share the same anatomy of a header, footer, and shaded background overlay.
Standard modals are basic containers with a close “X” and the ability the dismiss by clicking outside of the modal bounds. The primary action button is a primary system color, complimented by a grey cancel action.
The alert modal is to intended to focus the user on an urgent message that requires deliberate action. By contrast to standard modals, alert modals have no close “X”, nor do they allow for out of bounds dismissal. The primary action is always a system red with a grey cancel action.
Accessibility
We have built in functionality based on the recommendations for dialogs and modals in WAI-ARIA Authoring Practices 1.1.
- Upon opening, focus will be transferred to the first interactive element (unless
autofocus
is set to false) - Dialog element has
aria-modal="true"
- Explicitly exposes a
role
prop to control whetherdialog
oralertdialog
is used. Tab
key moves between focusable items (form inputs, footer buttons, etc). User should not be able to tab to items outside of modal.Escape
key closes the modal- Click on backdrop (anywhere outside dialog) hides modal.
- Background is not be scrollable while modal is open (position: fixed).
- Upon closing, focus should return to element that triggered modal.
Examples
The modal will by default focus the first interactive element.
If you want to focus something further down in the tab order, you can use the autoFocus
property.
This might be useful for targeting the most common action in the modal, such as a confirmation button.
In this example, the first interactive element (a button) is buried by the modal's content.
The normal behavior of the modal will be to skip past the content and focus on the interactive element.
In these cases, it is recommended by WAI-ARIA to avoid skipping content and focusing on a normally non-focusable element at the top of the content (such as an h1
or p
tag).
Ideally, we want to avoid an abrupt shift in context both visually and for screen-readers.
You can achieve this with the FocusOnce
utility component included in baseui/modal
.
To use it, wrap a non interactive element at the top of the modal in FocusOnce
.
This will allow the element to be targeted by autofocus
.
Once the user tabs away, the element will be removed from the tab ordering.
Notice that you need to handle modals closing order following their stacking order
when multiple modals are dismissed at the same time. This is important to have the body
scrolling restored in an expected way. See how the initial modal's close
function is
passed as a callback to the modal that is stacked on top of it toggleConfirm(false, close)
.
API
Modal API
animate
boolean
= true
Sets whether the Modal should be displayed by easing in and out
autofocus
boolean
= true
If true, focus will shift to the first interactive element within the modal. If false, the modal container itself will receive focus. Moving focus into a newly opened modal is important for accessibility purposes, so please be careful!
children
union
Modal content. The children-as-function API may be preferable for performance reasons (wont render until opened)
One of Node, => Node
closeable
boolean
= true
Whether the modal should be closeable by the user (either via escape, backdrop click, etc). You can set this to false if your modal has an action that the user must take before closing.
isOpen
boolean
= false
mountNode
HTMLElement
Where to mount the modal
HTMLElement
onClose
function
A callback that is invoked when the modal will close. Callback is passed a constant identifying what triggered the close.
closeSource $Keys{ closeButton: "closeButton", backdrop: "backdrop", escape: "escape" } => mixed
overrides
object
= {}
Root { component: ?ComponentType<<T> & { children: Node }>, props: ?{} | ({}) => ?{}, style: ?{} | ({}) => ?{} }<<T>> | ComponentType<<T> & { children: Node }>children Node$animate boolean required $isVisible boolean required $isOpen boolean required $size required One of $Keys{ default: "default", full: "full", auto: "auto" }, number, string$role required One of $Keys{ dialog: "dialog", alertdialog: "alertdialog" }, string$closeable boolean required Backdrop { component: ?ComponentType<<T> & { children: Node }>, props: ?{} | ({}) => ?{}, style: ?{} | ({}) => ?{} }<<T>> | ComponentType<<T> & { children: Node }>children Node$animate boolean required $isVisible boolean required $isOpen boolean required $size required One of $Keys{ default: "default", full: "full", auto: "auto" }, number, string$role required One of $Keys{ dialog: "dialog", alertdialog: "alertdialog" }, string$closeable boolean required Dialog { component: ?ComponentType<<T> & { children: Node }>, props: ?{} | ({}) => ?{}, style: ?{} | ({}) => ?{} }<<T>> | ComponentType<<T> & { children: Node }>children Node$animate boolean required $isVisible boolean required $isOpen boolean required $size required One of $Keys{ default: "default", full: "full", auto: "auto" }, number, string$role required One of $Keys{ dialog: "dialog", alertdialog: "alertdialog" }, string$closeable boolean required DialogContainer { component: ?ComponentType<<T> & { children: Node }>, props: ?{} | ({}) => ?{}, style: ?{} | ({}) => ?{} }<<T>> | ComponentType<<T> & { children: Node }>children Node$animate boolean required $isVisible boolean required $isOpen boolean required $size required One of $Keys{ default: "default", full: "full", auto: "auto" }, number, string$role required One of $Keys{ dialog: "dialog", alertdialog: "alertdialog" }, string$closeable boolean required Close { component: ?ComponentType<<T> & { children: Node }>, props: ?{} | ({}) => ?{}, style: ?{} | ({}) => ?{} }<<T>> | ComponentType<<T> & { children: Node }>children Node$animate boolean required $isVisible boolean required $isOpen boolean required $size required One of $Keys{ default: "default", full: "full", auto: "auto" }, number, string$role required One of $Keys{ dialog: "dialog", alertdialog: "alertdialog" }, string$closeable boolean required
role
union
=
Which accessibility role this modal should have.
One of $Keys{ dialog: "dialog", alertdialog: "alertdialog" }, string
size
union
=
Controls the size of the modal (primarily width). Can be a SIZE constant or css width property value.
One of $Keys{ default: "default", full: "full", auto: "auto" }, number, string