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 @@
- @switch (_getDisplayedMessages()) { - @case ('error') { -
- -
- } - - @case ('hint') { -
- @if (hintLabel) { - {{hintLabel}} - } - -
- -
+
+ +
+
+ @if (hintLabel) { + {{hintLabel}} } - } + +
+ +
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