Modal Dialog
A dialog is a window placed on either the page or another dialog. There are 2 types of dialogs: modal and non-modal. The background content under the modal dialog is inert.
Inert content outside an active dialog is visually dimmed and not reachable or actionable. The users are unable to interact with content outside an active dialog window.
NOTE:
- New to accessibility or uncertain of requirements, it will be helpful to review all sections below.
- Already familiar with requirements, skip to the “Working Example” section for sample HTML, CSS and JavaScript (when needed), along with a working demo.
-
The container that holds the dialog content SHOULD be specified with
role="dialog"
andaria-modal="true".
- The dialog SHOULD consist of a heading element.
-
The modal dialog SHOULD be provided with an accessible name.
-
Accessible name CAN be given using
aria-labelledby
attribute by referencing the id of the visual text if present in the dialog that can act as an accessible name as well. -
Accessible name CAN also be given using
aria-label
attribute if there is no visual text that can act as an accessible name.
-
Accessible name CAN be given using
-
Once the dialog is opened, the focus can be managed one of 2 ways:
-
Preferred approach is to set focus on the dialog container programmatically using a
tabindex="-1"
on the container and using JavaScript to relocate the focus. This method ensures assistive technologies will read the content of the dialog from the top down. - Alternatively, focus CAN be set to the first focusable element within the dialog. The drawback of this approach is that most often the first focusable element is the close button. Opening a dialog and announcement of “close button” doesn’t make for a good user experience.
-
Preferred approach is to set focus on the dialog container programmatically using a
- The keyboard focus SHOULD stay within the modal dialog.
- After the dialog is closed, keyboard focus MUST move back to the element that triggered the appearance of the dialog.
-
It is common practice and expected by many users that hitting the
ESC
key closes the dialog. -
DO NOT rely on
ESC
alone but include that functionality if you CAN. - A visible button to dismiss the modal dialog MUST be provided.
-
The background content CAN be hidden using
aria-hidden="true"
attribute as failsafe. Ensure that thearia-hidden
attribute is removed from the page source when users close the modal dialog. Additionally,tabindex="-1"
CAN be set on the interactive elements. -
When the dialog is not open it SHOULD be hidden from all users via
display: none;
property in CSS or using native HTMLhidden
attribute on the dialog container. -
When there is no triggering element to return to when a modal dialog is closed (e.g., cookie modal
dialog), the focus MUST be set on the first logical element on the page.
Note: The logical element CAN be either the first element of the page or the next logical element after the triggering element of the dialog.
For example,<div id="myModal" aria-labelledby="modal-headline" class="modal" tabindex="-1" role="dialog" aria-modal="true" aria-hidden="false" style="display: block;"> ... <h2 id="modal-headline" class="headline-text">Confirm add to Cart</h2> ... </div>
- The Color requirement MUST be met as per the content available in the dialog. For more information on meeting color requirements, refer to the Color Contrast and Color Alone components.
- As per the content available within the dialog, ensure the accessibility requirements are met. For more information on different elements to make accessible, refer to these components.
A well-defined modal dialogue majorly benefit the below users.
- People with cognitive disabilities
- People with visual disabilities
- People using speech input
- People using keyboard only
- People with limited dexterity
<h2>WriteToLearn Essentials Live Webinar 3 Hours</h2>
<p>
The 3-hour session will introduce participants to WriteToLearn and the
benefits of using it in the classroom. This session will include how to
navigate the software and how to set up accounts and classes in
WriteToLearn. Participants will learn how to use the essay and summary
writing components to encourage student engagement and to differentiate
their instruction. Price includes up to 30 people per session.
</p>
<p>
Training orders will be processed within 5-7 business days of order
placement. A training consultant will contact you to coordinate your
training. Training dates are scheduled 4-6 weeks from order placement.
</p>
<!-- Button to open the modal -->
<button class="button-primary" onclick="openModal()">Buy Item</button>
<!-- The Modal -->
<div id="myModal" aria-labelledby="modal-headline" class="modal" tabindex="-1" role="dialog" aria-modal="true" aria-hidden="true">
<div class="modal-content">
<h2 id="modal-headline" class="headline-text">Confirm add to Cart</h2>
<div id="purchaseForm">
<p class="form-row">
After adding the item to cart, follow the below steps:
</p>
<ul>
<li>Go to cart</li>
<li>
Click 'Choose dates' on the training title to choose the
preferred dates for the training
</li>
<li>Add the participant details.</li>
</ul>
</div>
<button class="button-primary" onclick="purchaseItem()">Add to Cart</button>
<button class="button-primary" onclick="closeModal()" >Cancel</button>
</div>
</div>
.modal {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.7);
}
.modal:focus {
outline-offset: 2px;
outline: 2px solid #101010;
}
/* Styles for the modal content */
.modal-content {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: #fff;
padding: 20px;
border: 1px solid #ccc;
border-radius: 5px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}
.modal-content ul { margin-top: 0; }
.modal-content ul li { margin: 8px 0; }
.close {
position: absolute;
top: 10px;
right: 10px;
cursor: pointer;
font-size: 18px;
}
button.button-primary {
background-color: #003057;
border: 2px solid #000;
border-radius: 10px;
color: #fff;
display: inline-block;
line-height: 1.15;
padding: 0.35rem 1rem;
width: auto;
text-align: center;
text-decoration: none;
cursor: pointer;
margin: 0 12px 0 0;
font-size: 1rem;
vertical-align: middle;
}
button.button-primary:hover,
button.button-primary:focus {
background-color: #068379;
outline-offset: 2px;
outline: 1px solid #101010;
}
.headline-text {
color: #151515;
line-height: 1.5;
margin: 0 0 20px;
}
#purchaseForm {
margin: 0 0 1.5rem;
display: flex;
flex-direction: column;
gap: 10px;
}
let modal = document.getElementById('myModal');
let openButton = document.querySelector('button');
function openModal() {
modal.style.display = 'block';
modal.setAttribute('aria-hidden', 'false');
openButton.setAttribute('aria-hidden', 'true');
modal.addEventListener('keydown', trapTabKey);
// Ensure the modal receives focus
modal.focus();
// Focus on the first focusable element within the modal content
let focusableElements = modal.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])');
let firstFocusable = focusableElements[0];
// firstFocusable.focus();
// Listen for the 'Esc' key press to close the modal
document.addEventListener('keydown', function(e) {
if (e.key === 'Escape') {
closeModal();
}
});
}
function closeModal() {
modal.style.display = 'none';
modal.setAttribute('aria-hidden', 'true');
openButton.setAttribute('aria-hidden', 'false');
openButton.focus();
}
function purchaseItem() {
alert('Item successfully added to cart. Follow instructions to complete your purchase.');
closeModal();
}
function trapTabKey(e) {
if (e.key === 'Tab') {
const focusableElements = modal.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])');
const firstFocusable = focusableElements[0];
const lastFocusable = focusableElements[focusableElements.length - 1];
if (e.shiftKey) {
if (document.activeElement === firstFocusable) {
e.preventDefault();
lastFocusable.focus();
}
} else {
if (document.activeElement === lastFocusable) {
e.preventDefault();
firstFocusable.focus();
}
}
}
}
Due to the nature of this demonstration, it is best
viewed full screen
.