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