Modal
A Modal is a page overlay that displays information and blocks interaction with the page until an action is taken or the Modal is dismissed.
const ModalTrigger = () => {// Modal propertiesconst [isOpen, setIsOpen] = React.useState(false);const handleOpen = () => setIsOpen(true);const handleClose = () => setIsOpen(false);const modalHeadingID = useUID();return (<div><Button variant="primary" onClick={handleOpen}>Open modal</Button><Modal ariaLabelledby={modalHeadingID} isOpen={isOpen} onDismiss={handleClose} size="default"><ModalHeader><ModalHeading as="h3" id={modalHeadingID}>Choose an author</ModalHeading></ModalHeader><ModalBody><Paragraph>“If there’s a book that you want to read, but it hasn’t been written yet, then you must write it.”— Toni Morrison</Paragraph><Label htmlFor="author">Choose an author</Label><Select id="author"><Option value="baldwin">James Baldwin</Option><Option value="brown">adrienne maree brown</Option><Option value="butler">Octavia Butler</Option><Option value="coates">Ta-Nehisi Coates</Option><Option value="lorde">Audre Lorde</Option><Option value="nnedi">Nnedi Okorafor</Option></Select></ModalBody><ModalFooter><ModalFooterActions><Button variant="secondary" onClick={handleClose}>Cancel</Button><Button variant="primary">Done</Button></ModalFooterActions></ModalFooter></Modal></div>);};render(<ModalTrigger />)
A Modal is a dialog that appears over the main content and moves the system into a special mode requiring user interaction. Modals are typically used to focus a user's attention for any of these scenarios:
- When you want to capture information from the user without having them leave the parent page.
- When you want to show additional information to the user without losing context of the parent page.
If you need to to guarantee a user acknowledges a critical piece of information, use an Alert Dialog instead.
Users cannot interact with content outside an active modal window until the user explicitly closes it. When the modal opens, focus moves to an element contained in it (by default, the first element that can be focused) in the modal, and the focus should stay in and cycle through the modal's content. Focus shouldn't return to the underlying page until the user closes the modal. This can happen in any of the following ways:
- Presses the Esc key
- Presses the close "x" button in the Modal header
- Presses a "Cancel" button in the Modal footer
- Clicks outside of the Modal
- Performs another action that closes the Modal
You can compose a Modal content area to support your use case, but elements such as Paragraph and Form Input are commonly used. See examples for common Modal patterns and dos/don'ts.
- All elements required to interact with the modal, including closing or acknowledging it, are contained in the modal since they trap focus, and users can't interact with the underlying page.
- Tabbing through a Modal will cycle through its content in the same way it does on a page. A Modal also supports pressing the Escape key to close the Modal.
- The element that serves as the modal container has a role of dialog.
- The modal must be labelled. It can be labelled either by:
- Setting a value for the
aria-labelledby
property that refers to a visibleModalHeading
. - Providing a label directly specifing by
aria-label
attribute on the Modal container.
- Setting a value for the
A modal is composed of:
- Header — Headers include a Heading and close button. Heading text should be concise (2-4 words and no more than one line) and describe the information or action the modal is presenting.
- Body — This container has no content requirements and allows you to compose a Modal as you need. Common components you might use include supporting body copy (with Paragraph) and form elements.
- Footer — This contains all possible modal actions aligned to the right side of the modal (by default) to show users they're progressing through their task, whether that's on the parent page, on a new page, or in another step in the modal.
Provide an accessible label
Be sure to assign the aria-labelledby
property on the modal container to the id of the modal heading.
A Modal has a default width of 608 px to allow for an optimal reading length at 70-75 characters per line at default Paragraph size at 100% magnification. At viewports smaller than 608 px, the Modal will fill the width of the viewport and pin to the bottom. The Modal will grow in height with the amount of content in it. Once the modal reaches 90% of the height of the viewport, the body will begin to scroll.
const ModalTrigger = () => {// Modal propertiesconst [isOpen, setIsOpen] = React.useState(false);const handleOpen = () => setIsOpen(true);const handleClose = () => setIsOpen(false);const modalHeadingID = useUID();return (<div><Button variant="primary" onClick={handleOpen}>Open modal</Button><Modal ariaLabelledby={modalHeadingID} isOpen={isOpen} onDismiss={handleClose} size="default"><ModalHeader><ModalHeading as="h3" id={modalHeadingID}>Choose an author</ModalHeading></ModalHeader><ModalBody><Paragraph>“If there’s a book that you want to read, but it hasn’t been written yet, then you must write it.”— Toni Morrison</Paragraph><Label htmlFor="author">Choose an author</Label><Select id="author"><Option value="baldwin">James Baldwin</Option><Option value="brown">adrienne maree brown</Option><Option value="butler">Octavia Butler</Option><Option value="coates">Ta-Nehisi Coates</Option><Option value="lorde">Audre Lorde</Option><Option value="nnedi">Nnedi Okorafor</Option></Select></ModalBody><ModalFooter><ModalFooterActions><Button variant="secondary" onClick={handleClose}>Cancel</Button><Button variant="primary">Done</Button></ModalFooterActions></ModalFooter></Modal></div>);};render(<ModalTrigger />)
Use a wide modal (816px) when your content requires it. For example, you may need to place a two-column Grid layout or video player in a wide modal.
At viewports smaller than 816 px, the Modal will shift to the default width (608px). The wide Modal follows all other sizing behavior as the default Modal.
const ModalTrigger = () => {// Modal propertiesconst [isOpen, setIsOpen] = React.useState(false);const handleOpen = () => setIsOpen(true);const handleClose = () => setIsOpen(false);const modalHeadingID = useUID();// Content propertiesconst [documentName, setDocumentName] = React.useState('');const [address1, setAddress1Name] = React.useState('');const [address2, setAddress2Name] = React.useState('');const documentNameInputID = useUID();const address1InputID = useUID();const address2InputID = useUID();return (<div><Button variant="primary" onClick={handleOpen}>Add supporting document</Button><Modal ariaLabelledby={modalHeadingID} isOpen={isOpen} onDismiss={handleClose} size="wide"><ModalHeader><ModalHeading as="h3" id={modalHeadingID}>Add supporting document</ModalHeading></ModalHeader><ModalBody><Grid gutter="space50"><Column><Box marginBottom="space50"><Label htmlFor={documentNameInputID}>Supporting document name</Label><Input onChange={(e) => setDocumentName(e.currentTarget.value)} id={documentNameInputID} type="text" value={documentName} /></Box><Box marginBottom="space50"><Label htmlFor={address1InputID}>Address 1</Label><Input onChange={(e) => setAddress1Name(e.currentTarget.value)} id={address1InputID} type="text" value={address1} /></Box><Box><Label htmlFor={address2InputID}>Address 2</Label><Input onChange={(e) => setAddress2Name(e.currentTarget.value)} id={address2InputID} type="text" value={address2} /></Box></Column><Column><Box backgroundColor="colorBackground" height="size20" display="flex" alignItems="center" justifyContent="center"><Text as="p" textAlign="center">Upload supporting document</Text></Box></Column></Grid></ModalBody><ModalFooter><ModalFooterActions><Button variant="secondary" onClick={handleClose}>Cancel</Button><Button variant="primary">Add document</Button></ModalFooterActions></ModalFooter></Modal></div>);};render(<ModalTrigger />)
When a Modal opens user focus is set inside the Modal. By default, user focus will be set on the first focusable element which is the close button. You can choose to explicitly set focus to any focusable UI control inside the modal.
To set a different initial focus target, set the initialFocusRef
prop on the Modal
container to a ref
of a focusable element inside the Modal.
const ModalTrigger = () => {// Modal propertiesconst [isOpen, setIsOpen] = React.useState(false);const handleOpen = () => setIsOpen(true);const handleClose = () => setIsOpen(false);const modalHeadingID = useUID();// ref of target intial focus elementconst nameInputRef = React.createRef();// Content propertiesconst [name, setName] = React.useState('');const inputID = useUID();return (<div><Button variant="primary" onClick={handleOpen}>New project</Button><ModalariaLabelledby={modalHeadingID}isOpen={isOpen}onDismiss={handleClose}// set inital focus hereinitialFocusRef={nameInputRef}size="default"><ModalHeader><ModalHeading as="h3" id={modalHeadingID}>Create a new project</ModalHeading></ModalHeader><ModalBody><Box as="form"><Label htmlFor={inputID}>Project Name</Label><Inputid={inputID}value={name}// assign the target ref hereref={nameInputRef}onChange={e => setName(e.currentTarget.value)}type="text"/></Box></ModalBody><ModalFooter><ModalFooterActions><Button variant="secondary" onClick={handleClose}>Cancel</Button><Button variant="primary">Submit</Button></ModalFooterActions></ModalFooter></Modal></div>);};render(<ModalTrigger />)
To internationalize the modal, simply pass different text as children to the Modal components. The only exception is the dismiss button in the ModalHeader
component–to change the button’s text, use the i18nDismissLabel
prop.
const ModalTrigger = () => {// Modal propertiesconst [isOpen, setIsOpen] = React.useState(false);const handleOpen = () => setIsOpen(true);const handleClose = () => setIsOpen(false);const modalHeadingID = useUID();return (<div><Button variant="primary" onClick={handleOpen}>Abrir modal</Button><Modal ariaLabelledby={modalHeadingID} isOpen={isOpen} onDismiss={handleClose} size="default"><ModalHeader i18nDismissLabel='Cerrar modal'><ModalHeading as="h3" id={modalHeadingID}>Escoja una autora</ModalHeading></ModalHeader><ModalBody><Paragraph>"Vivir en las fronteras y en los márgenes, mantener intacta la identidad múltiple y la integridad, es como tratar de nadar en un nuevo elemento, un elemento 'extranjero'"— Gloria E. Anzaldúa</Paragraph><Label htmlFor="author">Escoja una autora</Label><Select id="author"><Option value="allende">Isabel Allende</Option><Option value="cisneros">Sandra Cisneros</Option><Option value="santiago">Esmeralda Santiago</Option><Option value="anzaldúa">Gloria E. Anzaldúa</Option></Select></ModalBody><ModalFooter><ModalFooterActions><Button variant="secondary" onClick={handleClose}>Cancelar</Button><Button variant="primary">Confirmar</Button></ModalFooterActions></ModalFooter></Modal></div>);};render(<ModalTrigger />)
Include a header, body, and footer in your modal.
- The header should be concise (2-4 words), start with a verb, and clearly describe the information or action the modal presents.
- The body should expand on the topic in the header. If you need multiple sections of content with Headings in the body, use a Heading with the
heading40
variant. - The footers should include 1–2 actions aligned to the right side of the modal. Place the primary action farthest on the right to indicate to users they're progressing through their task.
By default the footer actions are aligned to the right of the modal using the Flexbox property justify-content
. This should be the most common configuration you should choose.
<ModalFooter><ModalFooterActions><Button variant="secondary">Cancel</Button><Button variant="primary">Save</Button></ModalFooterActions></ModalFooter>
Sometimes you may need to do left alignment of buttons. This is less common. To do so use the justify
property on the ModalFooterActions
component and set it to start
.
<ModalFooter><ModalFooterActions justify="start"><Button variant="secondary">Cancel</Button><Button variant="primary">Save</Button></ModalFooterActions></ModalFooter>
By using both alignment types, you are able to create directional alignments of footer actions.
<ModalFooter><ModalFooterActions justify="start"><Button variant="secondary">Back</Button></ModalFooterActions><ModalFooterActions><Button variant="secondary">Cancel</Button><Button variant="primary">Save</Button></ModalFooterActions></ModalFooter>
Use a Modal to:
- Request the user enter information to continue the current process.
- Guide the user through a complex workflow with a series of steps, while still maintaining context of the task that initiated the modal.
Do not use modals to show important warnings, since they can be dismissed without the user acknowledging the information. Instead, use an Alert Dialog.
Do not use modals to show error messages. Refer to the error state pattern for additional guidance on components.
Do
Use a clear and concise heading to describe the purpose of the Modal.
Don't
Don't go into unnecessary detail in the heading about the purpose of the Modal.
Do
Keep the main call to action in the footer. If you're asking the user to perform an action, use a primary action (primary button or destructive button). If you need only to give the user a way to close the Modal, use a secondary button or rely on the close 'x' button.
Don't
Don't put buttons that close the Modal, or confirm and submit content, in the body.
Do
Use at most one primary and one secondary action in a Modal. Make the secondary action a 'Cancel' button, especially when you want to give users an explicit choice to decline the primary action. This is especially useful when the primary action is a destructive action.
Don't
Don't put more than one primary action in the footer. Avoid using the secondary button for an action that isn't 'Close' or 'Cancel' since users will be used to pressing a secondary button that escapes the Modal. If you need to provide another action, add a third button to the footer, or consider showing it elsewhere.