diff --git a/package-lock.json b/package-lock.json index 4ebe758d1..52b9724d9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -36,6 +36,7 @@ "dompurify": "^3.2.5", "eventsource-parser": "^1.1.2", "file-saver": "^2.0.5", + "focus-trap": "^7.6.4", "fuse.js": "^7.0.0", "highlight.js": "^11.9.0", "html-entities": "^2.5.3", @@ -6801,9 +6802,10 @@ "dev": true }, "node_modules/focus-trap": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/focus-trap/-/focus-trap-7.5.4.tgz", - "integrity": "sha512-N7kHdlgsO/v+iD/dMoJKtsSqs5Dz/dXZVebRgJw23LDk+jMi/974zyiOYDziY2JPp8xivq9BmUGwIJMiuSBi7w==", + "version": "7.6.4", + "resolved": "https://registry.npmjs.org/focus-trap/-/focus-trap-7.6.4.tgz", + "integrity": "sha512-xx560wGBk7seZ6y933idtjJQc1l+ck+pI3sKvhKozdBV1dRZoKhkW5xoCaFv9tQiX5RH1xfSxjuNu6g+lmN/gw==", + "license": "MIT", "dependencies": { "tabbable": "^6.2.0" } diff --git a/package.json b/package.json index efd0f2cf3..f5e657152 100644 --- a/package.json +++ b/package.json @@ -79,6 +79,7 @@ "dompurify": "^3.2.5", "eventsource-parser": "^1.1.2", "file-saver": "^2.0.5", + "focus-trap": "^7.6.4", "fuse.js": "^7.0.0", "highlight.js": "^11.9.0", "html-entities": "^2.5.3", diff --git a/src/lib/components/common/Modal.svelte b/src/lib/components/common/Modal.svelte index 07f5c46af..e31a5248d 100644 --- a/src/lib/components/common/Modal.svelte +++ b/src/lib/components/common/Modal.svelte @@ -3,7 +3,7 @@ import { fade } from 'svelte/transition'; import { flyAndScale } from '$lib/utils/transitions'; - + import * as FocusTrap from 'focus-trap'; export let show = true; export let size = 'md'; export let containerClassName = 'p-3'; @@ -11,6 +11,10 @@ let modalElement = null; let mounted = false; + // Create focus trap to trap user tabs inside modal + // https://www.w3.org/WAI/WCAG21/Understanding/focus-order.html + // https://www.w3.org/WAI/WCAG21/Understanding/keyboard.html + let focusTrap: FocusTrap.FocusTrap | null = null; const sizeToWidth = (size) => { if (size === 'full') { @@ -45,9 +49,12 @@ $: if (show && modalElement) { document.body.appendChild(modalElement); + focusTrap = FocusTrap.createFocusTrap(modalElement); + focusTrap.activate(); window.addEventListener('keydown', handleKeyDown); document.body.style.overflow = 'hidden'; } else if (modalElement) { + focusTrap.deactivate(); window.removeEventListener('keydown', handleKeyDown); document.body.removeChild(modalElement); document.body.style.overflow = 'unset'; @@ -55,6 +62,9 @@ onDestroy(() => { show = false; + if (focusTrap) { + focusTrap.deactivate(); + } if (modalElement) { document.body.removeChild(modalElement); } @@ -66,6 +76,8 @@