Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

a11y-dialog

Package Overview
Dependencies
Maintainers
1
Versions
67
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

a11y-dialog - npm Package Compare versions

Comparing version 5.5.2 to 6.0.0

dist/a11y-dialog.d.ts

38

package.json
{
"name": "a11y-dialog",
"version": "5.5.2",
"version": "6.0.0",
"description": "A tiny script to make dialog windows accessible to assistive technology users.",
"homepage": "https://github.com/edenspiekermann/a11y-dialog",
"homepage": "https://github.com/HugoGiraudel/a11y-dialog",
"license": "MIT",
"main": "a11y-dialog.js",
"types": "a11y-dialog.d.ts",
"main": "dist/a11y-dialog.js",
"module": "dist/a11y-dialog.esm.js",
"types": "dist/a11y-dialog.d.ts",
"keywords": [

@@ -19,21 +20,14 @@ "modal",

"type": "git",
"url": "https://github.com/edenspiekermann/a11y-dialog"
"url": "https://github.com/HugoGiraudel/a11y-dialog"
},
"files": [
"a11y-dialog.js",
"a11y-dialog.min.js",
"a11y-dialog.d.ts"
"dist/*"
],
"scripts": {
"copy": "cp a11y-dialog.js example",
"minify": "uglifyjs a11y-dialog.js -o a11y-dialog.min.js -c -m",
"build": "npm run minify && npm run copy",
"postbuild": "npm run add-version",
"build": "rollup -c",
"serve": "npx serve example",
"test": "cypress run",
"extract-version": "cat package.json | grep version | head -1 | awk -F: '{ print $2 }' | sed 's/[\",]//g' | tr -d '[[:space:]]'",
"add-version": "echo \"/*! a11y-dialog $(npm run extract-version --silent) — © Edenspiekermann */\n$(cat a11y-dialog.min.js)\" > a11y-dialog.min.js",
"compress": "gzip -9 -fkc a11y-dialog.min.js > a11y-dialog.min.js.gz",
"show": "ls -lh a11y-dialog.min.js.gz | awk '{print \"Gzipped script size:\", $5\"B\"}'",
"size": "npm run build --silent && npm run compress --silent && npm run show --silent && rm a11y-dialog.min.js.gz",
"compress": "gzip -9 -fkc dist/a11y-dialog.min.js > dist/a11y-dialog.min.js.gz",
"show": "ls -lh dist/a11y-dialog.min.js.gz | awk '{print \"Gzipped script size:\", $5\"B\"}'",
"size": "npm run build -- --silent && npm run compress --silent && npm run show && rm dist/a11y-dialog.min.js.gz",
"docs:clean": "rm -rf _book",

@@ -43,3 +37,3 @@ "docs:prepare": "gitbook install",

"docs:watch": "npm run docs:prepare && gitbook serve",
"docs:publish": "npm run docs:clean && npm run docs:build && cd _book && git init && git commit --allow-empty -m 'Update book' && git checkout -b gh-pages && touch .nojekyll && git add . && git commit -am 'Update book' && git push git@github.com:edenspiekermann/a11y-dialog gh-pages --force"
"docs:publish": "npm run docs:clean && npm run docs:build && cd _book && git init && git commit --allow-empty -m 'Update book' && git checkout -b gh-pages && touch .nojekyll && git add . && git commit -am 'Update book' && git push git@github.com:HugoGiraudel/a11y-dialog gh-pages --force"
},

@@ -56,2 +50,4 @@ "husky": {

"devDependencies": {
"@rollup/plugin-commonjs": "^17.1.0",
"@rollup/plugin-node-resolve": "^11.2.0",
"cypress": "^6.4.0",

@@ -63,4 +59,8 @@ "cypress-plugin-tab": "^1.0.5",

"prettier": "^2.2.1",
"uglify-js": "^3.12.8"
"rollup": "^2.39.0",
"rollup-plugin-terser": "^7.0.2"
},
"dependencies": {
"focusable-selectors": "^0.2.0"
}
}

@@ -1,7 +0,6 @@

# [A11y Dialog](http://edenspiekermann.github.io/a11y-dialog/)
# [A11y Dialog](http://hugogiraudel.github.io/a11y-dialog/)
[a11y-dialog](http://edenspiekermann.github.io/a11y-dialog/) is a lightweight (1.6Kb) yet flexible script to create accessible dialog windows.
[a11y-dialog](http://hugogiraudel.github.io/a11y-dialog/) is a lightweight (1.6Kb) yet flexible script to create accessible dialog windows.
✔︎ No dependencies
✔︎ Leveraging the native `<dialog>` element
✔︎ Leveraging the native `<dialog>` element if desired
✔︎ Closing dialog on overlay click and <kbd>ESC</kbd>

@@ -14,15 +13,60 @@ ✔︎ Toggling `aria-*` attributes

You can try the [live demo ↗](http://edenspiekermann.github.io/a11y-dialog/example/).
You can try the [live demo ↗](http://hugogiraudel.github.io/a11y-dialog/example/).
## Installation
### Using a bundler (recommended)
If you’re using a bundler (such as Webpack or Rollup), you can install `a11y-dialog` through npm or yarn like any other dependency:
```sh
npm install a11y-dialog
```
npm install a11y-dialog --save
```sh
yarn add a11y-dialog
```
Then you can import the library in your JavaScript codebase to access the `A11yDialog` class and instantiate your dialogs as you intend to.
```js
import A11yDialog from 'a11y-dialog'
const container = document.querySelector('#my-dialog-container')
const dialog = new A11yDialog(container)
```
If you rely on the `data-a11y-dialog` attribute to automate the dialog [instantiation](#instantiation) in order not to write JavaScript at all, you could simplify the import as such:
```js
import 'a11y-dialog'
```
### Using a CDN
If you prefer loading `a11y-dialog` from a third-party CDN such as jsdelivr or unpkg, you can do so by adding this script tag in your HTML:
```html
<script
defer
src="https://cdn.jsdelivr.net/npm/a11y-dialog@6/dist/a11y-dialog.min.js"
></script>
```
If you intend to use ES modules, you can use the ESM version of script (from v6.0.0 onwards only):
```html
<script type="module">
import A11yDialog from 'https://cdn.jsdelivr.net/npm/a11y-dialog@6/dist/a11y-dialog.esm.min.js'
const container = document.querySelector('#my-dialog-container')
const dialog = new A11yDialog(container)
</script>
```
## Usage
You will find a concrete demo in the [example](https://github.com/edenspiekermann/a11y-dialog/tree/main/example) folder of this repository, but basically here is the gist:
You will find a concrete demo in the [example](https://github.com/HugoGiraudel/a11y-dialog/tree/main/example) folder of this repository, but basically here is the gist:
### Expected DOM structure
### HTML boilerplate

@@ -32,67 +76,19 @@ Here is the basic markup, which can be enhanced. Pay extra attention to the comments.

```html
<!--
Main container related notes:
- It can have a different id than `main`, however you will have to pass it as a second argument to the A11yDialog instance. See further down.
-->
<div id="main">
<!--
Here lives the main content of the page.
-->
</div>
<!--
Dialog container related notes:
- It is not the actual dialog window, just the container with which the script interacts.
- It can have a different id than `my-accessible-dialog`, but it needs an `id` anyway.
- It can have a different class, or no class at all—as long as your CSS accounts for that.
- It should have an initial `aria-hidden="true"` to avoid a “flash of unhidden dialog” on page load.
- It can have the `data-a11y-dialog` attribute (with the “targets” as value, see “Instantiation”) to automatically instantiate the dialog without JavaScript.
-->
<div class="dialog-container" id="my-accessible-dialog" aria-hidden="true">
<!--
Overlay related notes:
- It has to have the `tabindex="-1"` attribute.
- It doesn’t have to have the `data-a11y-dialog-hide` attribute, however this is recommended. It hides the dialog when clicking outside of it.
- It should not have the `data-a11y-dialog-hide` if the dialog window has the `alertdialog` role (see below).
-->
<!-- 1. The main content container -->
<div id="main"></div>
<!-- 2. The dialog container -->
<div id="your-dialog-id" aria-hidden="true">
<!-- 3. The dialog overlay -->
<div tabindex="-1" data-a11y-dialog-hide></div>
<!--
Dialog window content related notes:
- It is the actual visual dialog element.
- It may have the `alertdialog` role to make it behave like a “modal”. See the “Usage as a modal” section of the docs.
- It can be a `<dialog>` element without `role="dialog"`, but there might be browsers inconsistencies.
- It doesn’t have to have the `aria-labelledby` attribute however this is recommended. It should match the `id` of the dialog title.
-->
<div role="dialog" aria-labelledby="dialog-title">
<!--
Inner document related notes:
- It doesn’t have to exist but improves support in NVDA.
- It doesn’t have to exist when using <dialog> because is implied.
-->
<!-- 4. The actual dialog -->
<div role="dialog" aria-labelledby="your-dialog-title-id">
<!-- 5. The inner document -->
<div role="document">
<!--
Closing button related notes:
- It does have to have the `type="button"` attribute.
- It does have to have the `data-a11y-dialog-hide` attribute.
- It does have to have an aria-label attribute if you use an icon as content.
-->
<button
type="button"
data-a11y-dialog-hide
aria-label="Close this dialog window"
>
<!-- 6. The close button -->
<button type="button" data-a11y-dialog-hide aria-label="Close dialog">
&times;
</button>
<!--
Dialog title related notes:
- It should have a different content than `Dialog Title`.
- It can have a different id than `dialog-title`.
-->
<h1 id="dialog-title">Dialog Title</h1>
<!--
Here lives the main content of the dialog.
-->
<!-- 7. The dialog title -->
<h1 id="your-dialog-title-id">Your dialog title</h1>
<!-- 8. Dialog content -->
</div>

@@ -103,7 +99,62 @@ </div>

1. The main container is where your site/app content lives.
- It can have a different id than `main`, however you will have to pass it as a second argument to the A11yDialog instance. See [instantiation instructions](#instantiation) further down.
2. The dialog container.
- It is not the actual dialog window, just the container with which the script interacts.
- It can have a different id than `your-dialog-id`, but it needs an `id` anyway.
- It might need a class for you to be able to style it.
- It should have an initial `aria-hidden="true"` to avoid a “flash of unhidden dialog” on page load.
- It can have the `data-a11y-dialog` attribute (with the “targets” as value, see [Instantiation](#instantiation)) to automatically instantiate the dialog without JavaScript.
3. The dialog overlay.
- It has to have the `tabindex="-1"` attribute.
- It doesn’t have to have the `data-a11y-dialog-hide` attribute, however this is recommended. It hides the dialog when clicking outside of it.
- It should not have the `data-a11y-dialog-hide` if the dialog window has the `alertdialog` role (see below).
4. The actual dialog.
- It may have the `alertdialog` role to make it behave like a “modal”. See the [Usage as a modal](#usage-as-a-modal) section of the docs.
- It can be a `<dialog>` element, but there might be [browsers inconsistencies](#about-the-html-dialog-element).
- It doesn’t have to have the `aria-labelledby` attribute however this is recommended. It should match the `id` of the dialog title.
5. The inner document.
- It doesn’t have to exist but improves support in NVDA.
- It doesn’t have to exist when using `<dialog>` because is implied.
6. The dialog close button.
- It does have to have the `type="button"` attribute.
- It does have to have the `data-a11y-dialog-hide` attribute.
- It does have to have an `aria-label` attribute if you use an icon as content.
7. The dialog title.
- It should have a different content than “Dialog Title”.
- It can have a different id than `your-dialog-title-id`.
8. The dialog content.
- This is where your dialog content lives.
#### About the HTML dialog element
As mentioned in the comments above, the script works fine with the native HTML `<dialog>` element and will polyfill its behaviour so the dialog works in any browser, regardless of their support for that HTML element. However, it is recommended _not_ to use it and to rely on a `<div>` with `role="dialog"` instead. Amongst other, here are the issues with the HTML `<dialog>` element:
- Clicking the backdrop does not close the dialog on Chrome.
- The native `::backdrop` only shows when programatically opening the dialog, not when using the `open` attribute.
- Default styles are left to the browsers’ discretion and can be inconsistent.
- The [modal pattern](#usage-as-a-modal) (`role="alertdialog"`) simply does not work with the dialog element.
- It still requires JavaScript anyway, so it’s not even 100% HTML.
- [Read more about the shortcoming of the dialog element by Scott Ohara](https://www.scottohara.me/blog/2019/03/05/open-dialog.html).
### Styling layer
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.
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 content containers (where the rest of the site/app lives).
In browsers supporting the `<dialog>` element, its visibility will be handled by the user-agent itself. Until support gets better across the board, the styling layer is up to the implementor (you).
If using the `<dialog>` element (which is [not recommended due to browser inconsistencies](#about-the-html-dialog-element)), its visibility will be handled by the user-agent itself. If using a `<div>` with the `dialog` role (which is recommended for consistency), the styling layer is up to the implementor (you).

@@ -114,9 +165,11 @@ We recommend using at least the following styles to make everything work on both supporting and non-supporting user-agents:

/**
* When the native `<dialog>` element is supported, the overlay is implied and
* can be styled with `::backdrop`, which means the DOM one should be removed.
* When the native `<dialog>` element is supported and used, the overlay is
* handled natively and can be styled with `::backdrop`, which means the DOM one
* should be removed.
*
* The `data-a11y-dialog-native` attribute is set by the script when the
* `<dialog>` element is properly supported.
* `<dialog>` element is properly supported. Feel free to replace `:first-child`
* with the overlay selector you prefer.
*
* Feel free to replace `:first-child` with the overlay selector you prefer.
* This rule can be safely omitted when *not* using the <dialog> element.
*/

@@ -128,5 +181,7 @@ [data-a11y-dialog-native] > :first-child {

/**
* When the `<dialog>` element is not supported, its default display is `inline`
* which can cause layout issues. This makes sure the dialog is correctly
* displayed when open.
* When the `<dialog>` element is used but not supported by the user agent, its
* default display is `inline` which can cause layout issues. This makes sure
* the dialog is correctly displayed when open.
*
* This rule can be safely omitted when *not* using the <dialog> element.
*/

@@ -157,6 +212,6 @@ dialog[open] {

the selector containing the main website’s or app’s code.
See “Expected DOM structure” for more information. -->
See HTML boilerplate” for more information. -->
<div
class="dialog-container"
id="my-accessible-dialog"
id="your-dialog-id"
aria-hidden="true"

@@ -173,3 +228,3 @@ data-a11y-dialog="#root"

// Get the dialog container HTML element (with the accessor method you want)
const el = document.getElementById('my-accessible-dialog')
const el = document.getElementById('your-dialog-id')

@@ -180,3 +235,3 @@ // Instantiate a new A11yDialog module

As recommended in the [HTML section](#expected-dom-structure) of this documentation, the dialog element is supposed to be on the same level as your content container(s). Therefore, the script will toggle the `aria-hidden` attribute of the siblings of the dialog element as a default. You can change this behaviour by passing a `NodeList`, an `Element` or a selector as second argument to the `A11yDialog` constructor:
As recommended in the [HTML section](#html-boilerplate) of this documentation, the dialog element is supposed to be on the same level as your content container(s). Therefore, the script will toggle the `aria-hidden` attribute of the siblings of the dialog element as a default. You can change this behaviour by passing a `NodeList`, an `Element` or a selector as second argument to the `A11yDialog` constructor:

@@ -195,6 +250,6 @@ ```javascript

The following button will open the dialog with the `my-accessible-dialog` id when interacted with.
The following button will open the dialog with the `your-dialog-id` id when interacted with.
```html
<button type="button" data-a11y-dialog-show="my-accessible-dialog">
<button type="button" data-a11y-dialog-show="your-dialog-id">
Open the dialog

@@ -212,3 +267,3 @@ </button>

The following button will close the dialog with the `my-accessible-dialog` id when interacted with. Given that the only focusable elements when the dialog is open are the focusable children of the dialog itself, it seems rather unlikely that you will ever need this but in case you do, well you can.
The following button will close the dialog with the `your-dialog-id` id when interacted with. Given that the only focusable elements when the dialog is open are the focusable children of the dialog itself, it seems rather unlikely that you will ever need this but in case you do, well you can.

@@ -218,3 +273,3 @@ ```html

type="button"
data-a11y-dialog-hide="my-accessible-dialog"
data-a11y-dialog-hide="your-dialog-id"
aria-label="Close the dialog"

@@ -226,3 +281,3 @@ >

In addition, the library adds a `data-a11y-dialog-native` attribute (with no value) when the `<dialog>` element is natively supported. This attribute is essentially used to customise the styling layer based on user-agent support (or lack thereof).
In addition, the library adds a `data-a11y-dialog-native` attribute (with no value) when the `<dialog>` element is used and natively supported. This attribute is essentially used to customise the styling layer based on user-agent support (or lack thereof).

@@ -241,3 +296,3 @@ ### JS API

When the `<dialog>` element is natively supported, the argument passed to `show()` and `hide()` is being passed to the native call to [`showModal()`](https://www.w3.org/TR/html52/interactive-elements.html#dom-htmldialogelement-showmodal) and [`close()`](https://www.w3.org/TR/html52/interactive-elements.html#dom-htmldialogelement-close). If necessary, the `returnValue` can be read using `dialog.dialog.returnValue`.
When the `<dialog>` element is used and natively supported, the argument passed to `show()` and `hide()` is being passed to the native call to [`showModal()`](https://www.w3.org/TR/html52/interactive-elements.html#dom-htmldialogelement-showmodal) and [`close()`](https://www.w3.org/TR/html52/interactive-elements.html#dom-htmldialogelement-close). If necessary, the `returnValue` can be read using `<instance>.dialog.returnValue`.

@@ -261,3 +316,3 @@ 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.

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](https://developer.mozilla.org/en-US/docs/Web/API/Event) (if any).
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 container element and the [event object](https://developer.mozilla.org/en-US/docs/Web/API/Event) (if any).

@@ -299,3 +354,3 @@ The event object can be used to know which trigger (opener / closer) has been used in case of a `show` or `hide` event.

By default, a11y-dialog behaves as a dialog: it is closable with the <kbd>ESC</kbd> key, and by clicking the backdrop. However, it is possible to make it work like a “modal”, which would remove these features.
By default, a11y-dialog behaves as a dialog: it is closable with the <kbd>ESC</kbd> key, and by clicking the backdrop (provided the `data-a11y-dialog-hide` attribute is given to is). However, it is possible to make it work like a “modal”, which would remove these features.

@@ -312,4 +367,28 @@ To do so:

Nested dialogs is a [questionable design pattern](https://ux.stackexchange.com/questions/52042/is-it-acceptable-to-open-a-modal-popup-on-top-of-another-modal-popup) that is not referenced anywhere in the [HTML 5.2 Dialog specification](https://html.spec.whatwg.org/multipage/interactive-elements.html#the-dialog-element). Therefore it is discouraged and not supported by default by the library. That being said, if you still want to run with it, [Renato de Leão explains how in issue #80](https://github.com/edenspiekermann/a11y-dialog/issues/80#issuecomment-377691629).
Nesting dialogs is a [questionable design pattern](https://ux.stackexchange.com/questions/52042/is-it-acceptable-to-open-a-modal-popup-on-top-of-another-modal-popup) that is not referenced anywhere in the [HTML 5.2 Dialog specification](https://html.spec.whatwg.org/multipage/interactive-elements.html#the-dialog-element). Therefore it is actively discouraged in favour of clearer interface design.
That being said, it is supported by the library, under the following conditions:
- Dialogs should live next to each other in the DOM.
- The `targets` argument of the constructor or value of the `data-a11y-dialog` attribute of every dialog should _not_ include the other dialogs, only the main content container. For instance:
```html
<div id="main">
<!-- The main content container -->
</div>
<div id="dialog-1" data-a11y-dialog="#main">
<!-- Dialog 1 content + a button to open dialog 2 -->
</div>
<div id="dialog-2" data-a11y-dialog="#main">
<!-- Dialog 2 content + a button to open dialog 3 -->
</div>
<div id="dialog-3" data-a11y-dialog="#main">
<!-- Dialog 3 content -->
</div>
```
Pressing <kbd>ESC</kbd> or clicking the backdrop will only close the top-most dialog, while the other remain untouched. It essentially makes it possible to stack dialogs on top of each other, then closing them one at a time.
There is an example in the [example/tests](https://github.com/HugoGiraudel/a11y-dialog/blob/main/example/tests/nested-dialogs.html) directory of the repository, as well as an associated test in [cypress/integration](https://github.com/HugoGiraudel/a11y-dialog/blob/main/cypress/integration/nestedDialogs.html). The original feature request by Renato de Leão remains in [issue #80](https://github.com/HugoGiraudel/a11y-dialog/issues/80#issuecomment-377691629).
## Further reading

@@ -319,3 +398,3 @@

1. It has been reported that the focus restoration to the formerly active element when closing the dialog does not always work properly on iOS. It is unclear what causes this or even if it happens consistently. Refer to [issue #102](https://github.com/edenspiekermann/a11y-dialog/issues/102) as a reference.
1. It has been reported that the focus restoration to the formerly active element when closing the dialog does not always work properly on iOS. It is unclear what causes this or even if it happens consistently. Refer to [issue #102](https://github.com/HugoGiraudel/a11y-dialog/issues/102) as a reference.

@@ -322,0 +401,0 @@ 2. Content with `aria-hidden` appears to be sometimes read by VoiceOver on iOS and macOS. It is unclear in which case this happens, and does not appear to be an issue directly related to the library. Refer to this [WebKit bug](https://bugs.webkit.org/show_bug.cgi?id=201887#c2) for reference.

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc