npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

react-a11y-dialog

v7.4.0

Published

A React component wrapper and React hook around a11y-dialog.

Downloads

13,254

Readme

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 | Element \| 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).