Skip to content
Live coding ยท 30 minutes

Accessible modal dialog

Build a modal dialog component in React in 30 minutes. Start from an empty file and use no UI library. A button opens the dialog. The dialog has a title, some content, and a Close and a Confirm button. It must behave as a real dialog for mouse, keyboard and screen reader users. You may use the native dialog element or build the dialog from a div; say which one you choose and why. Explain your decisions while you code, as in a live round.

Requirements

  • A button opens the dialog; the Close button, the Escape key and a click on the backdrop close it
  • It is exposed as a modal dialog: the native dialog element opened with showModal, or role dialog with aria-modal set to true
  • It has an accessible name: aria-labelledby points to the title
  • When it opens, focus moves into the dialog, and Tab and Shift+Tab cannot reach the page behind
  • When it closes, focus returns to the button that opened it
  • The page behind does not scroll and cannot be used while the dialog is open
  • The component API is small: open, onClose, title and children

What reviewers look for

  • Correct semantics: the native dialog, or a role, aria-modal and a name
  • Focus management: in on open, kept inside while open, back on close
  • Effects clean up: key listeners are removed and the scroll lock is undone
  • The dialog is not cut off by a parent: the top layer of the native dialog, or a portal to the body
  • A small, clear API, with the open state owned by the parent
  • You say what you do and why, and you test with the keyboard before you say it is done

Check before you hand it in

  • The button opens the dialog, and the Close button, Escape and a click on the backdrop each close it
  • When it opens, focus is inside the dialog, and Tab and Shift+Tab do not reach the page behind
  • When it closes, focus returns to the button that opened it
  • It is a native dialog opened with showModal, or it has role dialog, aria-modal true and aria-labelledby that points to the title
  • The page behind does not scroll while the dialog is open, and scrolling works again after it closes
  • I explained each decision aloud while I coded, including the choice between the native dialog and a div
  • Open, close, focus in and focus back all worked within 30 minutes

If there is time

  • Build the other version too: a div with your own focus trap if you used the native dialog, or the reverse
  • Animate the opening and closing, and respect prefers-reduced-motion
  • Let the caller choose which element gets focus when the dialog opens