mirror of
https://github.com/zoriya/react-native-web.git
synced 2026-05-27 16:22:20 +00:00
[fix] Modal: refocus trigger-element after closing
Close #1821 Fix #1822
This commit is contained in:
committed by
Nicolas Gallagher
parent
e0cebea073
commit
58a8bbe094
@@ -123,6 +123,19 @@ const ModalFocusTrap = ({ active, children }: ModalFocusTrapProps) => {
|
||||
}
|
||||
}, [active]);
|
||||
|
||||
// To be fully compliant with WCAG we need to refocus element that triggered opening modal
|
||||
// after closing it
|
||||
useEffect(function() {
|
||||
if (canUseDOM) {
|
||||
const lastFocusedElementOutsideTrap = document.activeElement;
|
||||
return function() {
|
||||
if (lastFocusedElementOutsideTrap && document.contains(lastFocusedElementOutsideTrap)) {
|
||||
UIManager.focus(lastFocusedElementOutsideTrap);
|
||||
}
|
||||
};
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<FocusBracket />
|
||||
|
||||
@@ -280,6 +280,121 @@ describe('components/Modal', () => {
|
||||
expect(document.activeElement).toBe(insideElement);
|
||||
});
|
||||
|
||||
test('focus is brought back to the element that triggered modal after closing', () => {
|
||||
const { rerender } = render(
|
||||
<>
|
||||
<a data-testid={'outside'} href={'#outside'}>
|
||||
Outside
|
||||
</a>
|
||||
<Modal visible={false}>
|
||||
<a data-testid={'inside'} href={'#hello'}>
|
||||
Hello
|
||||
</a>
|
||||
</Modal>
|
||||
<a data-testid={'modal-trigger'} href={'#modal-trigger'}>
|
||||
Outside
|
||||
</a>
|
||||
</>
|
||||
);
|
||||
|
||||
const modalTrigger = document.querySelector('[data-testid="modal-trigger"]');
|
||||
modalTrigger.focus();
|
||||
expect(document.activeElement).toBe(modalTrigger);
|
||||
|
||||
rerender(
|
||||
<>
|
||||
<a data-testid={'outside'} href={'#outside'}>
|
||||
Outside
|
||||
</a>
|
||||
<Modal visible={true}>
|
||||
<a data-testid={'inside'} href={'#hello'}>
|
||||
Hello
|
||||
</a>
|
||||
</Modal>
|
||||
<a data-testid={'modal-trigger'} href={'#modal-trigger'}>
|
||||
Outside
|
||||
</a>
|
||||
</>
|
||||
);
|
||||
|
||||
const insideElement = document.querySelector('[data-testid="inside"]');
|
||||
expect(document.activeElement).toBe(insideElement);
|
||||
|
||||
rerender(
|
||||
<>
|
||||
<a data-testid={'outside'} href={'#outside'}>
|
||||
Outside
|
||||
</a>
|
||||
<Modal visible={false}>
|
||||
<a data-testid={'inside'} href={'#hello'}>
|
||||
Hello
|
||||
</a>
|
||||
</Modal>
|
||||
<a data-testid={'modal-trigger'} href={'#modal-trigger'}>
|
||||
Outside
|
||||
</a>
|
||||
</>
|
||||
);
|
||||
|
||||
expect(document.activeElement).toBe(modalTrigger);
|
||||
});
|
||||
|
||||
test('focus is brought back to the body when element that triggered modal is removed from the DOM after closing modal', () => {
|
||||
const { rerender } = render(
|
||||
<>
|
||||
<a data-testid={'outside'} href={'#outside'}>
|
||||
Outside
|
||||
</a>
|
||||
<Modal visible={false}>
|
||||
<a data-testid={'inside'} href={'#hello'}>
|
||||
Hello
|
||||
</a>
|
||||
</Modal>
|
||||
<a data-testid={'modal-trigger'} href={'#modal-trigger'}>
|
||||
Outside
|
||||
</a>
|
||||
</>
|
||||
);
|
||||
|
||||
const modalTrigger = document.querySelector('[data-testid="modal-trigger"]');
|
||||
modalTrigger.focus();
|
||||
expect(document.activeElement).toBe(modalTrigger);
|
||||
|
||||
rerender(
|
||||
<>
|
||||
<a data-testid={'outside'} href={'#outside'}>
|
||||
Outside
|
||||
</a>
|
||||
<Modal visible={true}>
|
||||
<a data-testid={'inside'} href={'#hello'}>
|
||||
Hello
|
||||
</a>
|
||||
</Modal>
|
||||
<a data-testid={'modal-trigger'} href={'#modal-trigger'}>
|
||||
Outside
|
||||
</a>
|
||||
</>
|
||||
);
|
||||
|
||||
const insideElement = document.querySelector('[data-testid="inside"]');
|
||||
expect(document.activeElement).toBe(insideElement);
|
||||
|
||||
rerender(
|
||||
<>
|
||||
<a data-testid={'outside'} href={'#outside'}>
|
||||
Outside
|
||||
</a>
|
||||
<Modal visible={false}>
|
||||
<a data-testid={'inside'} href={'#hello'}>
|
||||
Hello
|
||||
</a>
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
|
||||
expect(document.activeElement).toBe(document.body);
|
||||
});
|
||||
|
||||
test('focus is trapped when active', () => {
|
||||
render(
|
||||
<>
|
||||
|
||||
Reference in New Issue
Block a user