All questions

Modal Dialog IV

Premium

Modal Dialog IV

Finish the modal family with the part that makes it genuinely usable by keyboard and screen-reader users: focus management. When the dialog opens, focus moves into it; while it's open, Tab is trapped so it cycles within the dialog instead of leaking to the page behind; and when it closes, focus returns to the element that opened it. Get these three right and the modal works without a mouse.

Signature

// A self-contained component. No props.
function App(): JSX.Element;

The accessible, dismissable dialog from before, now with focus moved in on open, trapped while open, and restored on close.

Examples

open:               focus jumps from the trigger into the dialog (first control)
Tab at last item:   wraps to the first item (stays inside)
Shift+Tab at first: wraps to the last item (stays inside)
close:              focus returns to the "Open dialog" trigger
Three responsibilities:
  1. save document.activeElement, then focus the first item in the dialog
  2. on Tab / Shift+Tab at the edges, wrap focus (preventDefault)
  3. on close, restore focus to the saved element

Notes

  • Move focus in. On open, save the currently focused element, then focus the first focusable element inside the dialog so keyboard users start there.
  • Trap Tab. Find the dialog's focusable elements; when Tab would leave the last one (or Shift+Tab the first), preventDefault and wrap to the other end.
  • Restore on close. Focus the saved element so the user returns to where they were — typically the trigger button.
  • Premium / hard. This is the trickiest member: it combines refs, a focusable-element query, edge detection, and cleanup.

Unlock the solution & editor

  • Runnable editor + tests

    Solve in the browser with instant Jest feedback.

  • Detailed solutions

    Walkthroughs, edge cases, and complexity notes.

  • Multi-framework variants

    React, Vue, Vanilla, Angular — same question, different stacks.

Upgrade to Premium