Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion packages/unity-bootstrap-theme/src/js/modals.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,20 @@ function initModals() {
document
.getElementById("openModalButton")
?.addEventListener("click", function () {
document.getElementById("uds-modal").classList.add("open");
document.getElementById("uds-modal")?.classList.add("open");
document.getElementById("closeModalButton")?.focus();
});

document
.getElementById("closeModalButton")
?.addEventListener("click", function () {
document.getElementById("uds-modal").classList.remove("open");
});

document?.addEventListener("keydown", function (event) {
event.key === "Escape" &&
document.getElementById("uds-modal")?.classList.remove("open");
});
}

EventHandler.on(window, "load.uds.modals", initModals);
Expand Down
66 changes: 63 additions & 3 deletions packages/unity-react-core/src/components/Modal/Modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,70 @@ export const Modal: React.FC<ModalProps> = ({ open, gaData }) => {
setOpen(false);
};

useEffect(() => {
const handleKeyDown = (event: any) => {
if (event.key === "Escape") setOpen(false); // Close on Esc key
};

if (openState) {
document.addEventListener("keydown", handleKeyDown);
}

return () => document.removeEventListener("keydown", handleKeyDown);
}, [openState, setOpen]);

useEffect(() => {
if (!openState) return;

//source: https://stackoverflow.com/questions/4195616/how-to-set-the-focus-on-a-javascript-modal-window
const focusableElements =
'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])';
const modal = document.getElementsByClassName("uds-modal-container")[0];
const firstFocusableElement = modal?.querySelectorAll(focusableElements)[0];
const focusableContent = modal?.querySelectorAll(focusableElements);
const lastFocusableElement = focusableContent
? focusableContent[focusableContent?.length - 1]
: undefined;

const handleTabKey = (e: KeyboardEvent) => {
let isTabPressed = e.key === "Tab"; // || e.keyCode === 9;

if (!isTabPressed) {
return;
}

if (e.shiftKey) {
// if shift key pressed for shift + tab combination
if (document.activeElement === firstFocusableElement) {
(lastFocusableElement as HTMLElement)?.focus(); // add focus for the last focusable element
e.preventDefault();
}
} else {
// if tab key is pressed
if (document.activeElement === lastFocusableElement) {
// if focused has reached to last focusable element then focus first focusable element after pressing tab
(firstFocusableElement as HTMLElement)?.focus(); // add focus for the first focusable element
e.preventDefault();
}
}
};

if (lastFocusableElement && firstFocusableElement) {
document.addEventListener("keydown", handleTabKey);
(firstFocusableElement as HTMLElement)?.focus();
return () => document.removeEventListener("keydown", handleTabKey);
}
}, [openState]);

const modalTitle = "Content";

return (
<div className="container-fluid">
<button
type="button"
// data-bs-toggle={isBootstrap && "modal"}
// data-bs-target={isBootstrap && "#uds-modal"}
onClick={isReact && handleOpen}
onClick={isReact ? handleOpen : undefined}
id="openModalButton"
className="btn btn-dark"
>
Expand All @@ -60,20 +117,23 @@ export const Modal: React.FC<ModalProps> = ({ open, gaData }) => {
{(openState || isBootstrap) && (
<div
id="uds-modal"
role="dialog"
aria-modal="true"
aria-labelledby={modalTitle}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

aria-labelledby needs to reference an id this just points to a string of text. I would actually switch this to use aria-label instead of aria-labelledby.

className={classNames("uds-modal", { open: openState })}
>
<div className="uds-modal-container">
<GaEventWrapper gaData={{ ...defaultGaData, ...gaData }}>
<ButtonIconOnly
// @ts-ignore
id="closeModalButton"
onClick={isReact && handleClose}
onClick={isReact ? handleClose : undefined}
// data-bs-dismiss={isBootstrap && "modal"}
className="uds-modal-close-btn"
icon={["fas", "times"]}
/>
</GaEventWrapper>
<h1>Content</h1>
<h1>{modalTitle}</h1>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
eiusmod incididuntåç ut labore et dolore magna aliqua eiusmod
Expand Down