Hey folks, I’m wiring up a modal in a React-ish app and trying to keep it accessible, but after an async state update the focus trap seems to fight with VoiceOver/NVDA and sometimes announces the page behind the dialog (or focus jumps to the close button twice).
function openModal() {
setIsOpen(true);
// content inside modal loads async, so height + focusables change
requestAnimationFrame(() => {
const dialog = document.querySelector('[role="dialog"]');
dialog?.focus();
});
}
document.addEventListener('focusin', (e) => {
if (!isOpen) return;
const dialog = document.querySelector('[role="dialog"]');
if (dialog && !dialog.contains(e.target)) {
// bounce focus back in
dialog.focus();
}
});
What’s the most reliable pattern to keep focus inside a dynamically-rendered modal without causing screen readers to announce background content or “double focus” jumps?