diff --git a/packages/react-native-web/src/exports/Modal/ModalFocusTrap.js b/packages/react-native-web/src/exports/Modal/ModalFocusTrap.js
index b58227e06..9c3df9342 100644
--- a/packages/react-native-web/src/exports/Modal/ModalFocusTrap.js
+++ b/packages/react-native-web/src/exports/Modal/ModalFocusTrap.js
@@ -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 (
<>
diff --git a/packages/react-native-web/src/exports/Modal/__tests__/index.js b/packages/react-native-web/src/exports/Modal/__tests__/index.js
index 605bd23d6..8aeceb065 100644
--- a/packages/react-native-web/src/exports/Modal/__tests__/index.js
+++ b/packages/react-native-web/src/exports/Modal/__tests__/index.js
@@ -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(
+ <>
+
+ Outside
+
+
+
+ Hello
+
+
+
+ Outside
+
+ >
+ );
+
+ const modalTrigger = document.querySelector('[data-testid="modal-trigger"]');
+ modalTrigger.focus();
+ expect(document.activeElement).toBe(modalTrigger);
+
+ rerender(
+ <>
+
+ Outside
+
+
+
+ Hello
+
+
+
+ Outside
+
+ >
+ );
+
+ const insideElement = document.querySelector('[data-testid="inside"]');
+ expect(document.activeElement).toBe(insideElement);
+
+ rerender(
+ <>
+
+ Outside
+
+
+
+ Hello
+
+
+
+ Outside
+
+ >
+ );
+
+ 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(
+ <>
+
+ Outside
+
+
+
+ Hello
+
+
+
+ Outside
+
+ >
+ );
+
+ const modalTrigger = document.querySelector('[data-testid="modal-trigger"]');
+ modalTrigger.focus();
+ expect(document.activeElement).toBe(modalTrigger);
+
+ rerender(
+ <>
+
+ Outside
+
+
+
+ Hello
+
+
+
+ Outside
+
+ >
+ );
+
+ const insideElement = document.querySelector('[data-testid="inside"]');
+ expect(document.activeElement).toBe(insideElement);
+
+ rerender(
+ <>
+
+ Outside
+
+
+
+ Hello
+
+
+ >
+ );
+
+ expect(document.activeElement).toBe(document.body);
+ });
+
test('focus is trapped when active', () => {
render(
<>