Skip to content

Commit 845071c

Browse files
authored
fix(menu): hide from screen readers while animating (#30036)
Issue number: internal --------- <!-- Please do not submit updates to dependencies unless it fixes an issue. --> <!-- Please try to limit your pull request to one type (bugfix, feature, etc). Submit multiple pull requests if needed. --> ## What is the current behavior? <!-- Please describe the current behavior that you are modifying. --> When the menu is presented on an Android device, TalkBack's focus rings may appear in the wrong position due to the transition (specifically `transform` styles). This occurs because the focus rings are initially displayed at the starting position of the elements before the transition begins. ## What is the new behavior? <!-- Please describe the behavior or changes that are being added by this PR. --> - When an overlay is being animated (presenting or dismissing), the overlay will hide from screen readers. This allows Talkback to display the focus rings on the correct position. ## Does this introduce a breaking change? - [ ] Yes - [x] No <!-- If this introduces a breaking change: 1. Describe the impact and migration path for existing applications below. 2. Update the BREAKING.md file with the breaking change. 3. Add "BREAKING CHANGE: [...]" to the commit description when merging. See https://github.com/ionic-team/ionic-framework/blob/main/docs/CONTRIBUTING.md#footer for more information. --> ## Other information <!-- Any other information that is important to this PR such as screenshots of how the component looks before and after the change. --> Dev build: `8.4.1-dev.11732305980.19d90e1c` Related to #29951
1 parent f6188c4 commit 845071c

File tree

2 files changed

+37
-5
lines changed

2 files changed

+37
-5
lines changed

core/src/components/menu/menu.tsx

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import type { Attributes } from '@utils/helpers';
88
import { inheritAriaAttributes, assert, clamp, isEndSide as isEnd } from '@utils/helpers';
99
import { menuController } from '@utils/menu-controller';
1010
import { BACKDROP, GESTURE, getPresentedOverlay } from '@utils/overlays';
11+
import { isPlatform } from '@utils/platform';
1112
import { hostContext } from '@utils/theme';
1213

1314
import { config } from '../../global/config';
@@ -631,6 +632,23 @@ export class Menu implements ComponentInterface, MenuI {
631632
private beforeAnimation(shouldOpen: boolean, role?: string) {
632633
assert(!this.isAnimating, '_before() should not be called while animating');
633634

635+
/**
636+
* When the menu is presented on an Android device, TalkBack's focus rings
637+
* may appear in the wrong position due to the transition (specifically
638+
* `transform` styles). This occurs because the focus rings are initially
639+
* displayed at the starting position of the elements before the transition
640+
* begins. This workaround ensures the focus rings do not appear in the
641+
* incorrect location.
642+
*
643+
* If this solution is applied to iOS devices, then it leads to a bug where
644+
* the overlays cannot be accessed by screen readers. This is due to
645+
* VoiceOver not being able to update the accessibility tree when the
646+
* `aria-hidden` is removed.
647+
*/
648+
if (isPlatform('android')) {
649+
this.el.setAttribute('aria-hidden', 'true');
650+
}
651+
634652
// this places the menu into the correct location before it animates in
635653
// this css class doesn't actually kick off any animations
636654
this.el.classList.add(SHOW_MENU);
@@ -687,6 +705,17 @@ export class Menu implements ComponentInterface, MenuI {
687705
}
688706

689707
if (isOpen) {
708+
/**
709+
* When the menu is presented on an Android device, TalkBack's focus rings
710+
* may appear in the wrong position due to the transition (specifically
711+
* `transform` styles). The menu is hidden from screen readers during the
712+
* transition to prevent this. Once the transition is complete, the menu
713+
* is shown again.
714+
*/
715+
if (isPlatform('android')) {
716+
this.el.removeAttribute('aria-hidden');
717+
}
718+
690719
// emit open event
691720
this.ionDidOpen.emit();
692721

@@ -703,6 +732,8 @@ export class Menu implements ComponentInterface, MenuI {
703732
// start focus trapping
704733
document.addEventListener('focus', this.handleFocus, true);
705734
} else {
735+
this.el.removeAttribute('aria-hidden');
736+
706737
// remove css classes and unhide content from screen readers
707738
this.el.classList.remove(SHOW_MENU);
708739

core/src/utils/overlays.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -971,11 +971,12 @@ export const createTriggerController = () => {
971971
* like TalkBack do not announce or interact with the content until the
972972
* animation is complete, avoiding confusion for users.
973973
*
974-
* If the overlay is being presented, it prevents focus rings from appearing
975-
* in incorrect positions due to the transition (specifically `transform`
976-
* styles), ensuring that when aria-hidden is removed, the focus rings are
977-
* correctly displayed in the final location of the elements. This only
978-
* applies to Android devices.
974+
* When the overlay is presented on an Android device, TalkBack's focus rings
975+
* may appear in the wrong position due to the transition (specifically
976+
* `transform` styles). This occurs because the focus rings are initially
977+
* displayed at the starting position of the elements before the transition
978+
* begins. This workaround ensures the focus rings do not appear in the
979+
* incorrect location.
979980
*
980981
* If this solution is applied to iOS devices, then it leads to a bug where
981982
* the overlays cannot be accessed by screen readers. This is due to

0 commit comments

Comments
 (0)