Making Modal Windows Better For Everyone, again...

Back in September of 2014, my article "Making Modal Windows Better for Everyone", was published on Smashing Magazine. A ton of research and testing went into the writing of that article, and its accompanied demo. It's now been just shy of two years since the article's publication and while it still stands as an intro guide on how to build accessible modal windows, the code behind the modal window has evolved and I've learned ways in which to make the modal experience better.

Version 2

So what's different in version two of the accessible modal plug-in?

While it's been completely rewritten from the ground up, all the primary functions are still there:

  • Adding the appropriate ARIA attributes and expected mark-up elements to define the modal as a dialog window to assistive technologies (ATs).
  • Keeping track of the last focused element so that focus can return to it once the modal is closed.
  • Allowing for multiple options to close the modal window (close button, escape key, mouse click on overlay).
  • Trapping focus within the modal so that users can't tab out of it and interact with content that is obscured by the modal.

What's new with version 2:

  • The previous version required a developer to manually set some of the ARIA attributes and that could lead to instances where an attribute could be forgotten, and thus a developer would have to hunt through the mark-up and JavaScript to figure out what had been left out. This version of the plug-in makes sure that, as long as the .a11y-modal class is present, it will go through each modal instance and apply the necessary attributes, and even generate essential elements (like a close button) if they are not present.
  • Expanding on the first point, fail safes have been coded in to allow for the plug-in to be used with mark-up that may not totally be in your control.
    1. If there's no inherit modal heading element set for the modal's aria-labelledby attribute to reference, then the script will look for the first heading within the modal and set that to be the modal's label source.
    2. If there are no headings to be found within the modal at all, nor can a heading be added for whatever reason, then the modal script will next look to see if a data-set-modal-title was declared on the modal's trigger. If that attribute exists, then on activation, an aria-label will be added to the modal window using the same value as the data attribute.
    3. If neither a heading element exists within the modal, nor does the trigger have a data-set-modal-title, a generic aria-label="Dialog Window" will be assigned to the modal.
  • There are two types of modal dialog roles. The first being role="dialog" and the second, role="alertdialog". A data-modal-alert attribute can be set to 'true' on either a modal window instance, or a modal window's trigger to allow for this role to be applied with JavaScript.
  • Modals can be triggered via anchors or buttons. In situations where anchors are used to open modals, they are given the ARIA role="button" attribute, and keyboard controls are updated to allow both Enter and Space to activate.
  • As with version 1, modals are reordered to the top of the DOM to allow an updated trap focus function to keep focus within the modal window when navigating by tab, as well as to allow a user to SHIFT + tab backwards through the modal window and into the browser's address bar. To further ensure that screen readers and their additional methods of content navigation, do not have access the content beneath the modal overlay, a new <div id="a11y_body_wrap"> is generated to wrap all content within the body, sans the modal window. When a modal is open, this wrapper receives an aria-hidden="true" attribute to ensure that the content can not be accessed until the modal has been closed

    If you want to create your own wrapper element, or already have one in place, then the bodyWrapInit variable can be updated to reference the unique ID of your own wrapper, and the aria-hidden attribute will toggle that element instead.

  • More thought has been given to what should happen to modals in no JavaScript situations. Modal triggers that are <button>s are hidden when there's no JavaScript, as they simply won't function without it. Modal close buttons are also hidden, as they can't actually close anything without JavaScript and modal windows are set to be visible, in their original position in the document (hopefully after their trigger). Using a class of .no-js-hide-modal, modals can be set to display: none; and triggering their corresponding anchor, the CSS :target selector will reveal them to the user.

Demos & further details:

There is a Demo page hosted on GitHub with various tests to show off different setups for the modal script and its features.

Be sure to check out the ReadMe as well as the inline comments in the JavaScript. Basically everything is commented on to give insight into why the script does what it does.

Future Updates

While this version of the modal dialog script is written in jQuery, work on version 3 has already begun and it will go back to being written in vanilla JavaScript. I plan to include additional options for the modal as well as continuing to make any necessary modifications to ensure it meets expected functionality for all users.