Skip to main content

Accessible Modal Dialogs with Vanilla JS

Dialog Demos

Each of the following tests show off different features of the modal dialog script. For more information about the functionality and options of these dialog demos, see the modal dialog documentation on GitHub.

Test information

Each dialog will have different focus start points. And when each dialog is open, focus (via tab key or virtual cursor) should not be able to reach the document beneath the dialog. Browser chrome controls (browser buttons and address bar, etc.) should remain accessible.

The following dialogs have been tested with:

Modal Test 1 A single modal dialog launched from different triggers

Launch Modal 1 (link) Launch Modal 1 (span)

Modal Test 1 details

Each of the trigger elements are progressively enhanced (as needed) into buttons. They all open the same modal dialog.

Each "button" is assigned their own unique ID, when activated the ID of the specific button used will be stored in a var. The ID will be referred to again when the dialog is closed and focus needs to return to the specific element that opened it.

The dialog utilizes the value of data-modal-class to add the value as a class to itself, when JavaScript is available.

A close button is auto-generated from the script, as there are no manually set close buttons within the dialog.

In this example the dialog container is focused by default. This will result in JAWS + Firefox and VoiceOver (on desktop) announcing the accessible name and role of the dialog when its opened.

With JAWS and Internet Explorer 11, the accessible name and role of the dialog will be announced, and then the first child element of the dialog will be announced.

With NVDA and Firefox, NVDA will announce the accessible name of the dialog, but will not announce the role. It will then treat the dialog as if it was a new document loaded, and begin reading the contents of the dialog in sequential order.

Modal Test 1b A modal dialog with its heading autofocused

Launch Modal 1b

Modal Test 1b details

In this test the heading is set to receive autofocus.

Please note: that with default NVDA settings, NVDA will be verbose in the initial announcement of the dialog if the heading is focused by default. Ideally, the dialog container or a form control within a dialog should be the initially focused element. Per the latter, an aria-describedby should be used to provide a succinct description of the dialog's contents.

JAWS and VoiceOver will announce the name of the dialog, the dialog role, and then announce the heading text and element. For instance:

VoiceOver (desktop high sierra): Heading Text (from aria-labelledby), dialog, heading level 2, Heading Text".

JAWS (2018): Heading Text (from aria-labelledby), dialog, Heading Text, heading level 2.

NVDA (2018.1): Heading Text (from aria-labelledby), dialog, Heading Text, heading level 2. Heading Text. Heading level 2 Heading Text. all other contents of dialog are announced.

VoiceOver (iOS): Heading Text heading level 2.

Modal Test 2 A modal dialog with an autofocused, auto-generated, close button and visually hidden heading

Modal Test 2 details

Here the dialog has an auto-generated close button, which is focused when the dialog is opened. The text of the close button and a class are passed to the generated close button via the data-modal-close and data-modal-close-class attributes respectively. When an auto-generated close button has a text string set, it will not receive the styles of an "X" close button.

A data-modal-description has been added to the child element (in this case a p element), which serves as the primary description of the dialog. This attribute will trigger a function to setup an appropriate ID and aria-describedby for the dialog.

When the dialog is opened and the close button is focused, the accessible name of the dialog, its description, and the close button are all announced by screen readers.

Modal Test 3 A dialog containing an autofocused input

Modal Test 3 details

A dialog with an autofocused input. The description of the dialog consists of two paragraphs which are both wrapped in a div[data-modal-description].

As there are two buttons that serve to close the dialog (manually set "cancel" and "submit" buttons), an auto-generate close button will not be added to the dialog.

As the instance of the dialog is not 'destroyed' when a user hits the Esc key, or touches or clicks outside the dialog, if a user reopens the dialog, any value they added to the text input will remain. If a user activates the "cancel" button, the form will be reset, as the button has a type="reset".

Modal Test 4 A modal dialog with a nested form. An aria-describedby is set, but the dialog itself is focused to showcase how this will announce.

Launch Modal 4

Modal Test 4 details

Dialog with a manually set aria-describedby pointing to the description text of the dialog.

There is no autofocus set for this dialog as a test for what the announcement would be like in different screen readers for when the dialog wrapper receives focus by default.

NVDA will sequentially read through all the elements within the dialog unless a user begins to interact via keyboard controls.

VoiceOver will announce the accessible name and role of the dialog. After a short pause, it will read the aria-describedby content of the dialog.

JAWS + Firefox and Chrome will announce the accessible name and role of the dialog and the aria-describedby content of the dialog.

JAWS + IE11 will announce the accessible name and role of the dialog and the aria-describedby content of the dialog. It will then announce the first child (heading) and description of the dialog again.

Modal Test 5 An alert modal dialog

Launch Alert Modal

Modal Test 5 details

An alert dialog should be used when a response is required from a user. Where standard dialogs may allow for multiple passive ways to exit them, such as mouse clicking outside the dialog, or using a close button that provides no concrete commitment from a user that they actually engaged with the dialog's contents; an alert dialog should only be closed via purposeful button activations by a user.

For instance, an alert dialog may have a single "OK" button to indicate that the user is compliant with the message the dialog presents to them. Or a specific choice of "confirm" or "deny" buttons, to indicate that a user agrees or disagrees with the dialog's primary message.

With this in mind, it should be noted that an alert dialog will not auto generate close buttons. Authors should enter the specific actionable elements to dismiss the dialog. Alert dialogs do not allow for a mouse click or tap outside of the dialog to dismiss.

If an alert dialog contains a short message and a single actionable item, then that item may be autofocused, and the dialog may utilize aria-describedby to read out the contents of the dialog to the user, to decrease a user having to navigate the dialog themselves. If an alert dialog contains more than a confirmation button to dismiss it, e.g. there is a confirm, deny, or other choices to dismiss the dialog, then autofocusing a choice may lead some users to believe that is their only choice.

In this instance, the dialog itself should be given focus so a user can parse through the dialog and understand their options via their own discovery methods.