Skip to content

A very lightweight and flexible accessible modal dialog.

License

Notifications You must be signed in to change notification settings

faction23/a11y-dialog

 
 

Repository files navigation

mt-a11y-dialog is a lightweight yet flexible script to create accessible dialog windows. Forked from edenspiekermann

✔︎ No dependencies
✔︎ Closing dialog on overlay click and ESC
✔︎ Toggling aria-* attributes
✔︎ Trapping and restoring focus
✔︎ Firing events
✔︎ DOM and JS APIs
✔︎ Fast and tiny

Installation

npm install mt-a11y-dialog --save

Or you could also copy/paste the script in your project directly, but you will be disconnected from this repository, making it hard for your to get updates.

Usage

You will find a concrete demo in the example folder of this repository, but basically here is the gist:

Required Markup

All you require is a trigger, most likely a button since we want to be accessible, and then a script of type "text/template" which contains the contents of the dialog. Your trigger will need a "data-content" attribute which contains the string that the script tag has as its "data-js" attribute.

<button data-js="trigger-newsletter-signup" data-content="newsletter-signup-content">Open the dialog window</button>
<script data-js="newsletter-signup-content" type="text/template">
	HTML CONTENT
</script>

Styling layer

You will have to implement some styles for the dialog to “work” (visually speaking). The script itself does not take care of any styling whatsoever, not even the display property. It basically mostly toggles the aria-hidden attribute on the dialog itself and its counterpart containers. You can use this to show and hide the dialog:

.dialog[aria-hidden='true'] {
  display: none;
}

The example directory here has a styled modal you can use in your code for inspiration. You also have control over all the css classes used in the dialog as is explained further on.

Show/Hide Effects

To keep this library very light, we only provide a few low level utilities for animations, but with a bit of css you can do whatever you like.

50 milliseconds after the aria-hidden attribute is set to false on the root node a class of a11y-dialog--open is added.

This class is then removed on close, and if the effect type is set to css the aria-hidden attribute is set to true only after the effectSpeed time in milliseconds has passed, allowing whatever css animations you want to apply to run. You just have to synchronize your css animation timings you use with the effect speed.

The fade effect is handled for you in javascript and requires no css.

JavaScript instantiation

// Instantiate a new A11yDialog module
const dialog = new A11yDialog({ trigger: '.some-selector or an element node' });

Here are all the options you can pass to the dialog on init, and the defaults that the system uses:

appendTarget: '', // the dialog will be inserted after the button, you could supply a selector string here to override
bodyLock: true, // lock the body while dialog open?
closeButtonAriaLabel: 'Close this dialog window', // aria label for close button
closeButtonClasses: 'a11y-dialog__close-button', // classes for close button
contentClasses: 'a11y-dialog__content', // dialog content classes
effect: 'none', // none, fade, css
effectSpeed: 300, // effect speed in milliseconds
effectEasing: 'ease-in-out', // a css easing string
overlayClasses: 'a11y-dialog__overlay', // overlay classes
overlayClickCloses: true, // clicking overlay closes dialog
trigger: null, // the trigger for the dialog, can be selector string or element node
wrapperClasses: 'a11y-dialog', // the wrapper class for the dialog

JS API

Regarding the JS API, it simply consists of show() and hide() methods on the dialog instance.

// Show the dialog
dialog.show();

// Hide the dialog
dialog.hide();

For advanced usages, there are create() and destroy() methods. These are responsible for attaching click event listeners to dialog openers and closers. Note that the create() method is automatically called on instantiation so there is no need to call it again directly.

// Unbind click listeners from dialog openers and closers and remove all bound
// custom event listeners registered with `.on()`
dialog.destroy();

// Bind click listeners to dialog openers and closers
dialog.create();

Events

When shown, hidden and destroyed, the instance will emit certain events. It is possible to subscribe to these with the on() method which will receive the dialog DOM element and the event object (if any).

The event object can be used to know which trigger (opener / closer) has been used in case of a show or hide event.

dialog.on('render', function (dialogEl, event) {
  // The dialog is not rendered until the first time its called for by the trigger
  // Instantiate any js that needs to run on the dialog content here, like a slider init
});

dialog.on('show', function (dialogEl, event) {
  // Do something when dialog gets shown
  // Note: opener is `event.currentTarget`
});

dialog.on('hide', function (dialogEl, event) {
  // Do something when dialog gets hidden
  // Note: closer is `event.currentTarget`
});

dialog.on('destroy', function (dialogEl) {
  // Do something when dialog gets destroyed
});

dialog.on('create', function (dialogEl) {
  // Do something when dialog gets created
  // Note: because the initial `create()` call is made from the constructor, it
  // is not possible to react to this particular one (as registering will be
  // done after instantiation)
});

You can unregister these handlers with the off() method.

dialog.on('show', doSomething);
// …
dialog.off('show', doSomething);

Disclaimer & credits

This repository is a fork from edenspiekermann

About

A very lightweight and flexible accessible modal dialog.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • JavaScript 83.3%
  • HTML 16.7%