diff --git a/projects/core/src/features-config/feature-toggles/config/feature-toggles.ts b/projects/core/src/features-config/feature-toggles/config/feature-toggles.ts index e358b0b61d1..ef8d93788cc 100644 --- a/projects/core/src/features-config/feature-toggles/config/feature-toggles.ts +++ b/projects/core/src/features-config/feature-toggles/config/feature-toggles.ts @@ -119,6 +119,11 @@ export interface FeatureTogglesInterface { */ a11yNavigationUiKeyboardControls?: boolean; + /** + * Improves screen reader(VoiceOver, JAWS) narration of menu buttons inside of 'NavigationUIComponent'. + */ + a11yNavMenuExpandStateReadout?: boolean; + /** * Fixes heading gap present in 'OrderConfirmationItemsComponent' template. */ @@ -449,6 +454,7 @@ export const defaultFeatureToggles: Required = { a11yRequiredAsterisks: false, a11yQuantityOrderTabbing: false, a11yNavigationUiKeyboardControls: false, + a11yNavMenuExpandStateReadout: false, a11yOrderConfirmationHeadingOrder: false, a11yStarRating: false, a11yViewChangeAssistiveMessage: false, diff --git a/projects/storefrontapp/src/app/spartacus/spartacus-features.module.ts b/projects/storefrontapp/src/app/spartacus/spartacus-features.module.ts index 66c29b0e6dc..b57fee03ce9 100644 --- a/projects/storefrontapp/src/app/spartacus/spartacus-features.module.ts +++ b/projects/storefrontapp/src/app/spartacus/spartacus-features.module.ts @@ -292,6 +292,7 @@ if (environment.cpq) { a11yRequiredAsterisks: true, a11yQuantityOrderTabbing: true, a11yNavigationUiKeyboardControls: true, + a11yNavMenuExpandStateReadout: true, a11yOrderConfirmationHeadingOrder: true, a11yStarRating: true, a11yViewChangeAssistiveMessage: true, diff --git a/projects/storefrontlib/cms-components/navigation/navigation/navigation-ui.component.html b/projects/storefrontlib/cms-components/navigation/navigation/navigation-ui.component.html index b1dca5961d4..dd2c62db75a 100644 --- a/projects/storefrontlib/cms-components/navigation/navigation/navigation-ui.component.html +++ b/projects/storefrontlib/cms-components/navigation/navigation/navigation-ui.component.html @@ -88,6 +88,7 @@ [attr.aria-haspopup]="true" [attr.aria-expanded]="false" [attr.aria-label]="node.title" + [attr.aria-controls]="node.title" (click)="toggleOpen($any($event))" (mouseenter)="onMouseEnter($event)" (keydown.space)="onSpace($any($event))" @@ -116,7 +117,11 @@ -
+
    { + if (a11yKeyboardControlsEnabled || a11yNavMenuExpandStateReadout) { + const listItems = this.elemRef.nativeElement.querySelectorAll( + 'li.is-open:not(.back), li.is-opened' + ); + + if (a11yNavMenuExpandStateReadout) { + listItems.forEach((el: HTMLElement) => { + Array.from(el.children) + .filter((childNode) => childNode?.tagName === 'BUTTON') + .forEach((childNode) => { + this.renderer.setAttribute( + childNode, + ARIA_EXPANDED_ATTR, + 'false' + ); + }); + }); + } + if (a11yKeyboardControlsEnabled) { + listItems.forEach((el: HTMLElement) => { this.renderer.removeClass(el, 'is-open'); this.renderer.removeClass(el, 'is-opened'); }); - this.clear(); - this.renderer.removeClass(this.elemRef.nativeElement, 'is-open'); - this.updateClasses(); + this.clear(); + this.renderer.removeClass(this.elemRef.nativeElement, 'is-open'); + this.updateClasses(); + } } else if (this.openNodes?.length > 0) { this.renderer.removeClass(this.elemRef.nativeElement, 'is-open'); this.clear(); @@ -202,7 +225,7 @@ export class NavigationUIComponent implements OnInit, OnDestroy { Array.from(parentNode.children) .filter((childNode) => childNode?.tagName === 'BUTTON') .forEach((childNode) => { - this.renderer.setAttribute(childNode, 'aria-expanded', 'false'); + this.renderer.setAttribute(childNode, ARIA_EXPANDED_ATTR, 'false'); }); }); } @@ -223,7 +246,7 @@ export class NavigationUIComponent implements OnInit, OnDestroy { } } else { this.openNodes.push(parentNode); - this.renderer.setAttribute(node, 'aria-expanded', 'true'); + this.renderer.setAttribute(node, ARIA_EXPANDED_ATTR, 'true'); } this.updateClasses();