Skip to content

fix(modal): skip hidden elements when setting focus#1400

Draft
anusha-c18 wants to merge 1 commit into
canonical:mainfrom
anusha-c18:fix-modal-focus
Draft

fix(modal): skip hidden elements when setting focus#1400
anusha-c18 wants to merge 1 commit into
canonical:mainfrom
anusha-c18:fix-modal-focus

Conversation

@anusha-c18

@anusha-c18 anusha-c18 commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Done

  • Modal focus management now ignores hidden elements. The focus trap and initial focus only consider elements that are actually visible, so a hidden close button (or any hidden focusable element) no longer traps focus or breaks keyboard navigation.
  • Added tests covering the focus trap and initial focus behaviour when elements are hidden.

QA

Pinging @canonical/react-library-maintainers for a review.

Storybook

To see rendered examples of all react-components, run:

yarn start

QA in your project

from react-components run:

yarn build
npm pack

Install the resulting tarball in your project with:

yarn add <path-to-tarball>

QA steps

  • Verify the modal tests and confirm they pass.

Percy steps

  • List any expected visual change in Percy, or write something like "No visual changes expected" if none is expected.

Fixes

Fixes: #AC-4874

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Improves Modal focus management so hidden focusable elements don’t interfere with initial focus and the focus trap, addressing keyboard navigation issues when elements (e.g., the close button) are visually hidden.

Changes:

  • Filter focusable elements to only those considered visible when trapping focus on Tab/Shift+Tab.
  • Update initial-focus behavior to avoid focusing a hidden close button, falling back to the first visible focusable element.
  • Add tests covering focus trapping and initial focus when elements are hidden.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
src/components/Modal/Modal.tsx Adds visibility filtering for focusable elements and updates initial focus fallback logic.
src/components/Modal/Modal.test.tsx Adds tests for hidden elements in the focus trap and initial focus behavior when the close button is hidden.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +71 to +73
// determines whether an element is visible by checking computed styles
// fails open: an element is only treated as hiddenwhen getComputedStyle
// explicitly reports `display:none` or `visibility:hidden`
Comment on lines +132 to +136
if (isElementVisible(closeButtonRef.current)) {
closeButtonRef.current.focus();
} else {
(getVisibleFocusableElements()[0] ?? modalRef.current)?.focus();
}
Comment on lines +296 to +317
it("initially focuses the first visible focusable element when the close button is hidden", () => {
const style = document.createElement("style");
style.innerHTML = ".p-modal__close { display: none; }";
document.head.appendChild(style);

const { container } = render(
<Modal
title="Test"
close={jest.fn()}
buttonRow={<button id="test-cancel">Cancel</button>}
>
Bare bones
</Modal>,
);

const closeButton = container.querySelector("button.p-modal__close");
const cancelButton = container.querySelector("button#test-cancel");

expect(closeButton).not.toHaveFocus();
expect(cancelButton).toHaveFocus();
document.head.removeChild(style);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants