• Stars
    star
    173
  • Rank 220,124 (Top 5 %)
  • Language
    TypeScript
  • License
    MIT License
  • Created about 8 years ago
  • Updated about 2 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

An accessible React component for a11y-dialog

React A11yDialog

react-a11y-dialog provides a thin (~600b) React component and hook for a11y-dialog relying on React portals to ease the use of accessible dialog windows in React applications.

Version compatibility:

Special thanks to Moritz Krรถger (@morkro), Mayank (@mayank99) and EJ Mason (@mxmason) for their kind help in making that library better.

Install

npm install --save react-a11y-dialog

API

Name Type Required Default Description
id string true โ€”
ExpandThe HTML id attribute of the dialog element, internally used by a11y-dialog to manipulate the dialog.
title node true โ€”
ExpandThe title of the dialog, mandatory in the document to provide context to assistive technology. Could be hidden with CSS (while remaining accessible).
dialogRoot string false document.body
ExpandThe container for the dialog to be rendered into (React portalโ€™s root).
dialogRef function false () => {}
Expand A function called when the component has mounted, receiving the instance of A11yDialog so that it can be programmatically accessed later on.
titleId string false ${props.id}-title
ExpandThe HTML id attribute of the dialogโ€™s title element, used by assistive technologies to provide context and meaning to the dialog window.
closeButtonLabel string false Close this dialog window
ExpandThe HTML aria-label attribute of the close button, used by assistive technologies to provide extra meaning to the usual cross-mark.
closeButtonContent node false \u00D7 (ร—)
ExpandThe string that is the inner HTML of the close button.
closeButtonPosition string false first
ExpandWhether to render the close button as first element, last element or not at all. Options are: first, last and none. โš ๏ธ Caution! Setting it to none without providing a close button manually will be a critical accessibility issue.
classNames object false {}
ExpandObject of classes for each HTML element of the dialog element. Keys are: container, overlay, dialog, title, closeButton. See a11y-dialog docs for reference.
role string false dialog
ExpandThe role attribute of the dialog element, either dialog (default) or alertdialog to make it a modal (preventing closing on click outside of ESC key).

Hook

The library exports both A11yDialog, a React component rendering a dialog while performing the a11y-dialog bindings under the hood, and a useA11yDialog hook providing only the binding logic without any markup.

Using the hook can be handy when building your own dialog. Beware though, it is an advanced feature. Make sure to stick to the expected markup.

import { useA11yDialog } from 'react-a11y-dialog'

const MyCustomDialog = props => {
  // `instance` is the `a11y-dialog` instance.
  // `attr` is an object with the following keys:
  // - `container`: the dialog container
  // - `overlay`: the dialog overlay (sometimes called backdrop)
  // - `dialog`: the actual dialog box
  // - `title`: the dialog mandatory title
  // - `closeButton`:  the dialog close button
  const [instance, attr] = useA11yDialog({
    // The required HTML `id` attribute of the dialog element, internally used
    // a11y-dialog to manipulate the dialog.
    id: 'my-dialog',
    // The optional `role` attribute of the dialog element, either `dialog`
    // (default) or `alertdialog` to make it a modal (preventing closing on
    // click outside of ESC key).
    role: 'dialog',
  })

  const dialog = ReactDOM.createPortal(
    <div {...attr.container} className='dialog-container'>
      <div {...attr.overlay} className='dialog-overlay' />

      <div {...attr.dialog} className='dialog-content'>
        <p {...attr.title} className='dialog-title'>
          Your dialog title
        </p>

        <p>Your dialog content</p>

        <button {...attr.closeButton} className='dialog-close'>
          Close dialog
        </button>
      </div>
    </div>,
    document.body
  )

  return (
    <>
      <button type='button' onClick={() => instance.show()}>
        Open dialog
      </button>
      {dialog}
    </>
  )
}

Server-side rendering

The A11yDialog React component does not render anything on the server, and waits for client-side JavaScript to kick in to render the dialog through the React portal.

Mocking portals in tests

When youโ€™re using react-a11y-dialog in your unit tests, it might be necessary to mock React Portals and inject them to the root DOM before your tests are running. To accomplish that, create helper functions that attach all portals before a test and remove them afterwards.

const ROOT_PORTAL_IDS = ['dialog-root']

export const addPortalRoots = () => {
  for (const id of ROOT_PORTAL_IDS) {
    if (!global.document.querySelector('#' + id)) {
      const rootNode = global.document.createElement('div')
      rootNode.setAttribute('id', id)
      global.document.body.appendChild(rootNode)
    }
  }
}

export const removePortalRoots = () => {
  for (const id of rootPortalIds) {
    global.document.querySelector('#' + id)?.remove()
  }
}

And then use them in your tests.

describe('Testing MyComponent', () => {
  beforeAll(() => addPortalRoots())
  afterAll(() => removePortalRoots())
})

Example

The following example is a minimal setup of react-a11y-dialog. Additionally, you will need to add the required styles as per the recommendations from the a11y-dialog styling docs. How you integrate these styles is left to your discretion and depends on the styling layer youโ€™ve chosen for your project (classes, inline styles, CSS Modules, CSS-in-JSโ€ฆ). For anything but inline styles, styles will typically need to be passed via the classNames object prop, and as such will end up being applied to the elements rendered by React.

import { A11yDialog } from 'react-a11y-dialog'

const App = props => {
  const dialog = React.useRef()

  return (
    <div>
      <button type='button' onClick={() => dialog.current.show()}>
        Open the dialog
      </button>

      <A11yDialog
        id='my-accessible-dialog'
        dialogRef={instance => (dialog.current = instance)}
        title='The dialog title'
      >
        <p>Some content for the dialog.</p>
      </A11yDialog>
    </div>
  )
}

ReactDOM.render(<App />, document.querySelector('#root'))

Migrating to v7

Version 7 now relies on [email protected]. It should be largely backward compatible with version 6 though.

  • Make sure to read the a11y-dialog migration guide to adjust your a11y-dialog usage.
  • Typing has been consolidated.
  • Distribution has been improved (CJS + ESM, both normal and minified).
  • The A11yDialogInstance type is re-exported from a11y-dialog for convenience.

Migrating to v6

Version 6 now relies on [email protected]. See the a11y-dialog migration guide. Most notable changes requiring some update:

  • The inner container is no longer a thing.
  • The appRoot prop is no longer a thing.
  • The dialogRoot prop now defaults to document.body.
  • The useDialogElement prop is no longer supported (<dialog> is no longer supported).

More Repositories

1

sass-boilerplate

A boilerplate for Sass projects using the 7-1 architecture pattern from Sass Guidelines.
SCSS
3,338
star
2

a11y-dialog

A very lightweight and flexible accessible modal dialog script.
TypeScript
2,395
star
3

SJSJ

Simplified JavaScript Jargon
HTML
2,272
star
4

sass-guidelines

Guidelines for writing sane, maintainable and scalable Sass.
HTML
908
star
5

awesome-sass

A curated list of awesome Sass.
751
star
6

selectors-explained

A CSS selector to plain English translator.
JavaScript
211
star
7

SassyJSON

[UNMAINTAINED] A Sass API for JSON.
SCSS
169
star
8

jekyll-boilerplate

A cleaned up version of the initial Jekyll setup for quick use.
HTML
144
star
9

CRUD.js

A CRUD JavaScript class.
JavaScript
140
star
10

sass-compatibility

Sass compatibility issues between different engines.
SCSS
129
star
11

site

Sources for kittygiraudel.com
Liquid
103
star
12

Countdown.js

[UNMAINTAINED] A little JavaScript cutstomizable countdown
JavaScript
103
star
13

focusable-selectors

A micro-lib exporting an array of CSS selectors for focusable HTML elements.
JavaScript
74
star
14

SassyCast

[UNMAINTAINED] Type conversion functions for Sass.
SCSS
72
star
15

SassySort

[UNMAINTAINED] Several ways to sort values in Sass using popular sorting algorithms.
SCSS
61
star
16

ImagePreloader

A lightweight JavaScript implementation of an image preloader relying on Promises.
JavaScript
61
star
17

SassyStrings

[UNMAINTAINED] A collection of Sass functions to manipulate strings.
SCSS
59
star
18

react-menu-button

A React component wrapper around inclusive-menu-button.
JavaScript
50
star
19

ama

Ask me anything!
43
star
20

SassyTester

[UNMAINTAINED] A minimalistic function tester in Sass.
SCSS
42
star
21

dotfiles

My configuration files
Shell
40
star
22

react-a11y-disclosure

A small React hook to build accessible disclosure widgets.
JavaScript
35
star
23

react-a11y-footnotes

A reusable React implementation of accessible footnotes.
JavaScript
35
star
24

jekyll-styleguide

This project is an experiment about how we can create a living styleguide in Jekyll.
HTML
32
star
25

eleventy-plugin-footnotes

An 11ty plugin to render accessible footnotes with Liquid
JavaScript
32
star
26

github-release-search

Tiny CLI to search for terms in GitHub releases
JavaScript
28
star
27

SassyMatrix

[UNMAINTAINED] All you ever wanted to deal with matrices in Sass.
SCSS
28
star
28

node-legofy

Node.js version of Legofy.
JavaScript
25
star
29

SassyGradients

[UNMAINTAINED] Sass helpers to manipulate gradients.
SCSS
24
star
30

inline-styler

A teeny tiny JavaScript library to easily manipulate the style attribute of an element.
JavaScript
22
star
31

SassyBitwise

[UNMAINTAINED] Bitwise operators in Sass.
SCSS
18
star
32

dhand

A React hook to guess the dominant hand of the user.
JavaScript
18
star
33

scrabble-helper

A CLI helper for Scrabble.
JavaScript
15
star
34

sass-semver

[UNMAINTAINED] A Sass implementation of node-semver.
SCSS
13
star
35

SassyIteratorsGenerators

[UNMAINTAINED] Iterators and generators implementation in Sass.
SCSS
13
star
36

map-dater

An interactive command line utility to estimate the age of an undated world map.
JavaScript
13
star
37

SassyLogger

[UNMAINTAINED] A logger for Sass.
SCSS
13
star
38

circularray

A fast circular array implementation in JavaScript
JavaScript
13
star
39

hangman.js

Redux powered hangman game.
JavaScript
11
star
40

advent-of-code

TypeScript
6
star
41

sanity-micro-client

JavaScript
6
star
42

dependency-checker

A simple CLI script to check dependencies from a package.json
JavaScript
6
star
43

css3-pratique

CSS 3, Pratique du Design Web
4
star
44

sudoku-solver

JavaScript
4
star
45

PHP-hangman-game

[UNMAINTAINED] A little OOPHP hangman game.
PHP
3
star
46

cypress-5570

JavaScript
2
star
47

teachable-backup

Node.js script to download all content from a Teachable school
JavaScript
1
star