feat: modal accessibility and escape key features for unity react and… - #1753
feat: modal accessibility and escape key features for unity react and…#1753spaceperson wants to merge 2 commits into
Conversation
|
Storybook deployed at https://unity-uds-staging.s3.us-west-2.amazonaws.com/pr-1753/index.html |
davidornelas11
left a comment
There was a problem hiding this comment.
changes in comments
| id="uds-modal" | ||
| role="dialog" | ||
| aria-modal="true" | ||
| aria-labelledby={modalTitle} |
There was a problem hiding this comment.
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.
|
|
||
| const handleOpen = () => { | ||
| setOpen(true); | ||
| focusOnModalInput(); |
There was a problem hiding this comment.
focusOnModalInput() runs synchronously right after setOpen(true), but React hasn't re-rendered yet. #uds-modal-container doesn't exist in the DOM on first open, so modal here resolves to undefined and no focus/trap gets set. Move this logic into a useEffect keyed on openState instead, so it runs after the DOM updates.
Claude suggested this refactor but feel free to come up with another solution if you dont think it works well:
const handleOpen = () => {
setOpen(true);
};
const handleClose = () => {
setOpen(false);
};
useEffect(() => {
if (!openState) return;
const focusableElements =
'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])';
const modal = document.getElementsByClassName("uds-modal-container")[0];
const focusableContent = modal?.querySelectorAll<HTMLElement>(focusableElements);
const firstFocusableElement = focusableContent?.[0];
const lastFocusableElement = focusableContent?.[focusableContent.length - 1];
firstFocusableElement?.focus();
const handleTabKey = (e: KeyboardEvent) => {
if (e.key !== "Tab" || !firstFocusableElement || !lastFocusableElement) return;
if (e.shiftKey && document.activeElement === firstFocusableElement) {
lastFocusableElement.focus();
e.preventDefault();
} else if (!e.shiftKey && document.activeElement === lastFocusableElement) {
firstFocusableElement.focus();
e.preventDefault();
}
};
document.addEventListener("keydown", handleTabKey);
return () => document.removeEventListener("keydown", handleTabKey);
}, [openState]);
… bootstrap
Description
Checklist
Important Reminders
Links