diff --git a/src/material/form-field/form-field.html b/src/material/form-field/form-field.html
index 0c62f7ca809f..1998def69b3e 100644
--- a/src/material/form-field/form-field.html
+++ b/src/material/form-field/form-field.html
@@ -97,27 +97,25 @@
diff --git a/src/material/form-field/form-field.ts b/src/material/form-field/form-field.ts
index d2adfeb097fc..9622e2492eb0 100644
--- a/src/material/form-field/form-field.ts
+++ b/src/material/form-field/form-field.ts
@@ -428,6 +428,7 @@ export class MatFormField
this._stateChanges = control.stateChanges.subscribe(() => {
this._updateFocusState();
this._syncDescribedByIds();
+ this._showOrHideSubscript();
this._changeDetectorRef.markForCheck();
});
@@ -469,17 +470,20 @@ export class MatFormField
// Re-validate when the number of hints changes.
this._hintChildren.changes.subscribe(() => {
this._processHints();
+ this._showOrHideSubscript();
this._changeDetectorRef.markForCheck();
});
// Update the aria-described by when the number of errors changes.
this._errorChildren.changes.subscribe(() => {
this._syncDescribedByIds();
+ this._showOrHideSubscript();
this._changeDetectorRef.markForCheck();
});
// Initial mat-hint validation and subscript describedByIds sync.
this._validateHints();
+ this._showOrHideSubscript();
this._syncDescribedByIds();
}
@@ -649,6 +653,7 @@ export class MatFormField
}
if (this._getDisplayedMessages() === 'hint') {
+ this._showOrHideSubscript();
const startHint = this._hintChildren
? this._hintChildren.find(hint => hint.align === 'start')
: null;
@@ -673,6 +678,54 @@ export class MatFormField
}
}
+ /**
+ * Solves https://github.com/angular/components/issues/29616
+ * Issues with certain browser and screen reader pairings not able to announce mat-error
+ * when it's added to the DOM rather than changing the visibility of the hint/error wrappers.
+ * Changing visibility instead of adding the div wrappers works for all browsers and screen
+ * readers.
+ *
+ * If there is an 'error' or 'hint' message being returned, remove visibility: hidden
+ * style class and show error or hint section of code. If no 'error' or 'hint' messages are
+ * being returned and no error children showing in query list, add visibility: hidden
+ * style class back to error wrapper.
+ */
+ private _showOrHideSubscript() {
+ switch (this._getDisplayedMessages()) {
+ case 'error': {
+ console.log('Show error wrapper');
+ console.log(this._elementRef.nativeElement.children[1].children[0].classList);
+ this._elementRef.nativeElement.children[1].children[0].classList.remove(
+ 'cdk-visually-hidden',
+ );
+ // Can't show error message and hint at same time
+ console.log('Hide hint wrapper');
+ this._elementRef.nativeElement.children[1].children[1].classList.add('cdk-visually-hidden');
+ console.log(this._elementRef.nativeElement.children[1].children[0].classList);
+ break;
+ }
+ case 'hint': {
+ console.log('Show hint wrapper');
+ console.log(this._elementRef.nativeElement.children[1].children[1].classList);
+ this._elementRef.nativeElement.children[1].children[1].classList.remove(
+ 'cdk-visually-hidden',
+ );
+ console.log(this._elementRef.nativeElement.children[1].children[1].classList);
+ break;
+ }
+ }
+
+ if (!this._errorChildren || this._errorChildren.length === 0 || !this._control.errorState) {
+ console.log('hide error wrapper');
+ this._elementRef.nativeElement.children[1].children[0].classList.add('cdk-visually-hidden');
+ }
+
+ if (!this._hintChildren) {
+ console.log('hide hint wrapper');
+ this._elementRef.nativeElement.children[1].children[1].classList.add('cdk-visually-hidden');
+ }
+ }
+
/**
* Updates the horizontal offset of the label in the outline appearance. In the outline
* appearance, the notched-outline and label are not relative to the infix container because