diff --git a/src/material-experimental/mdc-snack-bar/BUILD.bazel b/src/material-experimental/mdc-snack-bar/BUILD.bazel index b4e1dfd266b6..bdf80ba2c8b7 100644 --- a/src/material-experimental/mdc-snack-bar/BUILD.bazel +++ b/src/material-experimental/mdc-snack-bar/BUILD.bazel @@ -69,6 +69,7 @@ ng_test_library( ":mdc-snack-bar", "//src/cdk/a11y", "//src/cdk/overlay", + "//src/cdk/platform", "@npm//@angular/common", "@npm//@angular/platform-browser", ], diff --git a/src/material-experimental/mdc-snack-bar/snack-bar-container.html b/src/material-experimental/mdc-snack-bar/snack-bar-container.html index eb5fdb1b7f61..25e3e89b3e19 100644 --- a/src/material-experimental/mdc-snack-bar/snack-bar-container.html +++ b/src/material-experimental/mdc-snack-bar/snack-bar-container.html @@ -10,6 +10,6 @@ -
+ diff --git a/src/material-experimental/mdc-snack-bar/snack-bar-container.ts b/src/material-experimental/mdc-snack-bar/snack-bar-container.ts index 258032aceb9c..296a75d1a514 100644 --- a/src/material-experimental/mdc-snack-bar/snack-bar-container.ts +++ b/src/material-experimental/mdc-snack-bar/snack-bar-container.ts @@ -86,6 +86,12 @@ export class MatSnackBarContainer extends BasePortalOutlet /** Whether the snack bar is currently exiting. */ _exiting = false; + /** + * Role of the live region. This is only for Firefox as there is a known issue where Firefox + + * JAWS does not read out aria-live message. + */ + _role?: 'status' | 'alert'; + private _mdcAdapter: MDCSnackbarAdapter = { addClass: (className: string) => this._setClass(className, true), removeClass: (className: string) => this._setClass(className, false), @@ -132,6 +138,17 @@ export class MatSnackBarContainer extends BasePortalOutlet this._live = 'polite'; } + // Only set role for Firefox. Set role based on aria-live because setting role="alert" implies + // aria-live="assertive" which may cause issues if aria-live is set to "polite" above. + if (this._platform.FIREFOX) { + if (this._live === 'polite') { + this._role = 'status'; + } + if (this._live === 'assertive') { + this._role = 'alert'; + } + } + // `MatSnackBar` will use the config's timeout to determine when the snack bar should be closed. // Set this to `-1` to mark it as indefinitely open so that MDC does not close itself. this._mdcFoundation.setTimeoutMs(-1); diff --git a/src/material-experimental/mdc-snack-bar/snack-bar.spec.ts b/src/material-experimental/mdc-snack-bar/snack-bar.spec.ts index c7bd0574f4c3..e485934eeeee 100644 --- a/src/material-experimental/mdc-snack-bar/snack-bar.spec.ts +++ b/src/material-experimental/mdc-snack-bar/snack-bar.spec.ts @@ -21,6 +21,7 @@ import { MatSnackBarModule, MatSnackBarRef, } from './index'; +import {Platform} from '@angular/cdk/platform'; describe('MatSnackBar', () => { let snackBar: MatSnackBar; @@ -161,6 +162,30 @@ describe('MatSnackBar', () => { .toBe('off', 'Expected snack bar container live region to have aria-live="off"'); }); + it('should have role of `alert` with an `assertive` politeness (Firefox only)', () => { + const platform = TestBed.inject(Platform); + snackBar.openFromComponent(BurritosNotification, {politeness: 'assertive'}); + viewContainerFixture.detectChanges(); + + const containerElement = overlayContainerElement.querySelector('mat-mdc-snack-bar-container')!; + const liveElement = containerElement.querySelector('[aria-live]')!; + + expect(liveElement.getAttribute('role')) + .toBe(platform.FIREFOX ? 'alert' : null); + }); + + it('should have role of `status` with an `polite` politeness (Firefox only)', () => { + const platform = TestBed.inject(Platform); + snackBar.openFromComponent(BurritosNotification, {politeness: 'polite'}); + viewContainerFixture.detectChanges(); + + const containerElement = overlayContainerElement.querySelector('mat-mdc-snack-bar-container')!; + const liveElement = containerElement.querySelector('[aria-live]')!; + + expect(liveElement.getAttribute('role')) + .toBe(platform.FIREFOX ? 'status' : null); + }); + it('should have exactly one MDC label element when opened through simple snack bar', () => { let config: MatSnackBarConfig = {viewContainerRef: testViewContainerRef}; snackBar.open(simpleMessage, simpleActionLabel, config); diff --git a/src/material/snack-bar/BUILD.bazel b/src/material/snack-bar/BUILD.bazel index fe9d3b934f17..010da3ff7c8c 100644 --- a/src/material/snack-bar/BUILD.bazel +++ b/src/material/snack-bar/BUILD.bazel @@ -65,6 +65,7 @@ ng_test_library( ":snack-bar", "//src/cdk/a11y", "//src/cdk/overlay", + "//src/cdk/platform", "@npm//@angular/common", "@npm//@angular/platform-browser", ], diff --git a/src/material/snack-bar/snack-bar-container.html b/src/material/snack-bar/snack-bar-container.html index 32a293bba0c7..334df5db9bdb 100644 --- a/src/material/snack-bar/snack-bar-container.html +++ b/src/material/snack-bar/snack-bar-container.html @@ -1,7 +1,7 @@ - + - + diff --git a/src/material/snack-bar/snack-bar-container.ts b/src/material/snack-bar/snack-bar-container.ts index 9116587a7b37..d0b3112940b7 100644 --- a/src/material/snack-bar/snack-bar-container.ts +++ b/src/material/snack-bar/snack-bar-container.ts @@ -98,6 +98,12 @@ export class MatSnackBarContainer extends BasePortalOutlet /** aria-live value for the live region. */ _live: AriaLivePoliteness; + /** + * Role of the live region. This is only for Firefox as there is a known issue where Firefox + + * JAWS does not read out aria-live message. + */ + _role?: 'status' | 'alert'; + constructor( private _ngZone: NgZone, private _elementRef: ElementRef