A Guide to Creating an Accessible Modal Dialog
A modal dialog allows a user to enter information or provide a prompt to a various action initiated by the user while interacting with the application. A modal dialog on the web has various use cases such as the following:
- Display a view for a user account registration / login.
- Temporarily block the main window to allow a file to be uploaded to the application.
- Allowing a user to select preferences allowed by the application which may include various configuration options.
- Provide warning prompt when a user tries to perform an operation that is not allowed.
Since a modal dialog appears on top of the body's main content, there are various approaches one can use to design the look and feel of the modal dialog. The target environment for designing the modal dialog for this tutorial is the browser. The modal dialog will be centered on the browser window and it will be placed on top of the other HTML body contents.
The modal dialog above has a backdrop which is just a view with a dark background color displayed above the main content. The dialog contents consists of a button to close the modal dialog and form to collect a user's information.
The code below displays the CSS styling for the modal dialog.
The desired behavior for the modal dialog is not to displayed unless when it is explicitly opened. This may occur if a user opens it by clicking a button and thus changing its displayed property. The modal backdrop spans the full screen by removing it from the normal document flow and positioning it relative to the body's block top, left, right and bottom positions.
The modal dialog content is also removed from the normal flow of the document and then it is positioned 50% relatively to the top and left of the body. To center the modal dialog contents, the modal's wrapper is moved 50% negative to both the X and Y axis of the document.
A modal dialog should be implemented in such a manner that the main content is not in interactive mode when the modal dialog's view is displayed. When using the keyboard to navigate the page, the focus should not go outside the modal dialog once it is active.
First, create variables to store the references of the modal dialog elements and a variable to hold the prior element that had focus before opening the modal:
The accessible modal dialog implementation for this solution requires four functions whose definitions are described below:
openModal()- Opens the modal dialog and provides functionality to interact with the modal dialog.
closeModal()- Closes the modal dialog.
keyDown()- Key down event handler function (useful when using the keyboard to interact with the dialog)
getFirstAndLastFocusableElements()- Fetches the references to the first and last tabbable elements on the modal dialog.
To follow along, add the initial function definitions for the above functions as shown below:
Opening and closing the modal dialog
The display property of the modal is toggled when opening and closing the modal. On opening the modal, the modal and its backdrop display properties are set to block while when closing the modal, the display properties of the modal and its backdrop are set to none. The
activeElement property of the document gets the object that currently has focus. The active element prior to opening the modal is the element used to open the modal.
You can add more flexibility to the process of closing the modal dialog by allowing a user to press the
ESC key on the keyboard or clicking on the modal backdrop to execute the
With the above implementation, one can open and close the modal dialog. Note that at the moment, you can't close the modal when you press the
ESC key. We will implement the functionality in the next section.
Maintaining focus inside the modal
The modal dialog is functional but still has some accessibility concerns for keyboard users of the application. To achieve accessibility guidelines required for a modal dialog, we need to maintain keyboard focus inside the modal and track where the focus is at the modal contents elements.
The references to the first and last tabbable elements inside the modal have to be fetched and focus is to be set appropriately when using either the
TAB key or a combination of
Shift + TAB keys.
Fetching the first and last tabbable elements inside the modal requires us having the list of all focusable elements in the DOM. You can narrow down the contents of the focusable elements for your use case by having only the elements that are focusable inside your modal dialog.
Since you may add other focusable elements in the modal at a later point in time, its best for us to use the list of all focusable elements in the DOM. The focusable elements are fetched from the modal as a node list (A collection of nodes inside the DOM). The first and last focusable elements then are at the first and last positions of the node list.
openDialog() function, store the references to the first and last tabbable elements on the modal dialog as
lastTabbedElement respectively using the object destructuring syntax:
In order to maintain focus inside the modal, set the first tabbable element to focus and then check which keyboard key a user has pressed while interacting with the modal. The keyboard keys we are going to look for are the
TAB and a combination of the keys
Shift + TAB.
When the modal is opened, set the first tabbable element on the modal to focus then listen to keydown event to check which keyboard key the user has pressed. If the keyboard key is
ESC then close the dialog box.
On pressing the
TAB key, check if the current active element is the last tabbable element in the modal, and update the focusable element to be the first tabbable element in the modal if the condition is true. If the user pressed a combination of the
Shift + TAB keys, check if the current active element is the first tabbable element in the modal, if so then update the focusable element to be the last tabbable element in the modal.
The focus is now maintained inside the modal when using the keyboard to navigate inside the modal. With above implementation, the modal dialog becomes accessible to your users.
The code for this tutorial is found here: https://github.com/khwilo/accessible-modal-dialog.
- What is a Modal Dialog Window? (September 28, 2011): https://ux.stackexchange.com/questions/12045/what-is-a-modal-dialog-window
- Design pattern for modal dialogs: https://www.w3.org/TR/wai-aria-practices/#dialog_modal
- A11y solutions - Modals: https://a11y-solutions.stevenwoodson.com/solutions/focus/modals/
- NodeList - https://developer.mozilla.org/en-US/docs/Web/API/NodeList
- DocumentOrShadowRoot.activeElement: https://developer.mozilla.org/en-US/docs/Web/API/DocumentOrShadowRoot/activeElement
- Focusable Elements - Browser Compatibility Table: https://allyjs.io/data-tables/focusable.html