Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(overlay): hide from screen readers while animating #29951

Merged
merged 27 commits into from
Oct 24, 2024
Merged
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
68f11a2
test(action-sheet): dev build tests
thetaPC Oct 14, 2024
be4a504
test(action-sheet): simplify styles
thetaPC Oct 14, 2024
a42ad86
test(action-sheet): add tabIndex, revert styles
thetaPC Oct 15, 2024
6ced157
test(action-sheet): strip code
thetaPC Oct 15, 2024
3240e88
test(action-sheet): change styles
thetaPC Oct 15, 2024
1415d7b
test(action-sheet): remove button state
thetaPC Oct 15, 2024
d05ced8
test(action-sheet): strip 1
thetaPC Oct 15, 2024
94d2c73
test(ac): header only
thetaPC Oct 16, 2024
f2984ab
test(ac): float
thetaPC Oct 16, 2024
37ea30f
test(ac): improve focus trapping
thetaPC Oct 16, 2024
a03b562
test(ac): change styles
thetaPC Oct 16, 2024
9c80de6
test(ac): revert logic
thetaPC Oct 17, 2024
993dcca
test(ac): update header format
thetaPC Oct 17, 2024
69c59d0
test(ac): use h2 and update styles
thetaPC Oct 17, 2024
b16c045
test(ac): add original styles
thetaPC Oct 17, 2024
f2a43f8
test(ac): revert to og styles pt 2
thetaPC Oct 17, 2024
bd5dc0b
tet(ac): revert og styles pt 3
thetaPC Oct 17, 2024
0b8ac51
test(ac): revert og styles pt 4
thetaPC Oct 17, 2024
b70f53f
test(ac): revert og styles pt 5
thetaPC Oct 17, 2024
c3d74ad
test(ac): revert og styles and move tabs
thetaPC Oct 17, 2024
f5e7494
test(ac): comment out transform
thetaPC Oct 17, 2024
60820bb
test(ac): transform changes
thetaPC Oct 17, 2024
294f665
test(ac): hide during animation
thetaPC Oct 17, 2024
36fe7f1
test(ac): move to overlays
thetaPC Oct 18, 2024
491efca
test(ac): revert backdrop
thetaPC Oct 18, 2024
94c165c
refactor(overlay): hide from screen readers while animating
thetaPC Oct 18, 2024
bc2c086
refactor(overlay): add comment
thetaPC Oct 23, 2024
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
40 changes: 38 additions & 2 deletions core/src/utils/overlays.ts
Original file line number Diff line number Diff line change
Expand Up @@ -514,7 +514,8 @@ export const present = async <OverlayPresentOptions>(

document.body.classList.add(BACKDROP_NO_SCROLL);

hideOverlaysFromScreenReaders(overlay.el);
hideUnderlyingOverlaysFromScreenReaders(overlay.el);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Just changed the name to distinguish between this function and the next.

hideAnimatingOverlayFromScreenReaders(overlay.el);

overlay.presented = true;
overlay.willPresent.emit();
Expand Down Expand Up @@ -560,6 +561,11 @@ export const present = async <OverlayPresentOptions>(
* it would still have aria-hidden on being presented again.
* Removing it here ensures the overlay is visible to screen
* readers.
*
* If this overlay was being presented, then it was hidden
* from screen readers during the animation. Now that the
* animation is complete, we can reveal the overlay to
* screen readers.
*/
overlay.el.removeAttribute('aria-hidden');
};
Expand Down Expand Up @@ -644,6 +650,13 @@ export const dismiss = async <OverlayDismissOptions>(
overlay.presented = false;

try {
/**
* There is no need to show the overlay to screen readers during
* the dismiss animation. This is because the overlay will be removed
* from the DOM after the animation is complete.
*/
hideAnimatingOverlayFromScreenReaders(overlay.el);

// Overlay contents should not be clickable during dismiss
overlay.el.style.setProperty('pointer-events', 'none');
overlay.willDismiss.emit({ data, role });
Expand Down Expand Up @@ -929,6 +942,29 @@ export const createTriggerController = () => {
};
};

/**
* The overlay that is being animated also needs to hide from screen
* readers during its animation. This ensures that assistive technologies
* like TalkBack do not announce or interact with the content until the
* animation is complete, avoiding confusion for users.
*
* If the overlay is being presented, it prevents focus rings from appearing
* in incorrect positions due to the transition (specifically `transform`
* styles), ensuring that when aria-hidden is removed, the focus rings are
* correctly displayed in the final location of the elements.
*
* @param overlay - The overlay that is being animated.
*/
const hideAnimatingOverlayFromScreenReaders = (overlay: HTMLIonOverlayElement) => {
if (doc === undefined) return;

/**
* Once the animation is complete, this attribute will be removed.
* This is done at the end of the `present` method.
*/
overlay.setAttribute('aria-hidden', 'true');
Copy link
Member

Choose a reason for hiding this comment

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

Optional: maybe add a comment referencing where the attribute is being added. My initial thought was: when we set it here, will it ever be removed somewhere else?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

};

/**
* Ensure that underlying overlays have aria-hidden if necessary so that screen readers
* cannot move focus to these elements. Note that we cannot rely on focus/focusin/focusout
Expand All @@ -939,7 +975,7 @@ export const createTriggerController = () => {
* @param newTopMostOverlay - The overlay that is being presented. Since the overlay has not been
* fully presented yet at the time this function is called it will not be included in the getPresentedOverlays result.
*/
const hideOverlaysFromScreenReaders = (newTopMostOverlay: HTMLIonOverlayElement) => {
const hideUnderlyingOverlaysFromScreenReaders = (newTopMostOverlay: HTMLIonOverlayElement) => {
if (doc === undefined) return;

const overlays = getPresentedOverlays(doc);
Expand Down
Loading