Skip to content

Commit

Permalink
fix(modal): ensure the call to action element is focused on close
Browse files Browse the repository at this point in the history
  • Loading branch information
tomdavies73 committed Sep 25, 2024
1 parent c5580bb commit d3ad27a
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/components/modal/modal.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ const Modal = ({
modalRef: ref,
setTriggerRefocusFlag,
topModalOverride,
focusCallToActionElement: true,
});

let background;
Expand Down
27 changes: 27 additions & 0 deletions src/hooks/__internal__/useModalManager/useModalManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ type UseModalManagerArgs = {
setTriggerRefocusFlag?: (flag: boolean) => void;
triggerRefocusOnClose?: boolean;
topModalOverride?: boolean;
focusCallToActionElement?: boolean;
};

const useModalManager = ({
Expand All @@ -17,9 +18,12 @@ const useModalManager = ({
setTriggerRefocusFlag,
triggerRefocusOnClose = true,
topModalOverride = false,
focusCallToActionElement = false,
}: UseModalManagerArgs) => {
const listenerAdded = useRef(false);
const modalRegistered = useRef(false);
const lastFocusedElement = useRef<HTMLElement | null>(null);
const modalOpenOnRender = useRef(false);

const handleClose = useCallback(
(ev: KeyboardEvent) => {
Expand Down Expand Up @@ -67,6 +71,14 @@ const useModalManager = ({
(ref: HTMLElement | null) => {
/* istanbul ignore else */
if (!modalRegistered.current) {
// Only sets the last focused element if a modal is not already open and there is no other active element previously
if (
!lastFocusedElement.current &&
!modalOpenOnRender.current &&
focusCallToActionElement
) {
lastFocusedElement.current = document.activeElement as HTMLElement;
}
ModalManager.addModal(ref, setTriggerRefocusFlag, topModalOverride);

modalRegistered.current = true;
Expand All @@ -80,17 +92,32 @@ const useModalManager = ({
if (modalRegistered.current) {
ModalManager.removeModal(ref, triggerRefocusOnClose);

if (focusCallToActionElement) {
setTimeout(() => {
// focuses the last active element before the modal was opened
lastFocusedElement.current?.focus();
}, 0);
}

modalRegistered.current = false;
}
},
[triggerRefocusOnClose]
);

// Creates a ref to check if the modal was open on render
useEffect(() => {
if (open) {
modalOpenOnRender.current = true;
}
}, []);

useEffect(() => {
const ref = modalRef.current;
if (open) {
registerModal(ref);
} else {
modalOpenOnRender.current = false;
unregisterModal(ref);
}
}, [modalRef, open, registerModal, unregisterModal]);
Expand Down

0 comments on commit d3ad27a

Please sign in to comment.