Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(material/form-field): changes show/hide mechanism of mat-error for screenreaders #29831

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 18 additions & 20 deletions src/material/form-field/form-field.html
Original file line number Diff line number Diff line change
Expand Up @@ -97,27 +97,25 @@

<div
class="mat-mdc-form-field-subscript-wrapper mat-mdc-form-field-bottom-align"
aria-atomic="true"
aria-live="assertive"
[class.mat-mdc-form-field-subscript-dynamic-size]="subscriptSizing === 'dynamic'"
>
@switch (_getDisplayedMessages()) {
@case ('error') {
<div
class="mat-mdc-form-field-error-wrapper"
[@transitionMessages]="_subscriptAnimationState"
>
<ng-content select="mat-error, [matError]"></ng-content>
</div>
}

@case ('hint') {
<div class="mat-mdc-form-field-hint-wrapper" [@transitionMessages]="_subscriptAnimationState">
@if (hintLabel) {
<mat-hint [id]="_hintLabelId">{{hintLabel}}</mat-hint>
}
<ng-content select="mat-hint:not([align='end'])"></ng-content>
<div class="mat-mdc-form-field-hint-spacer"></div>
<ng-content select="mat-hint[align='end']"></ng-content>
</div>
<div
class="mat-mdc-form-field-error-wrapper"
[@transitionMessages]="_subscriptAnimationState"
>
<ng-content select="mat-error, [matError]"></ng-content>
</div>
<div
class="mat-mdc-form-field-hint-wrapper"
[@transitionMessages]="_subscriptAnimationState"
>
@if (hintLabel) {
<mat-hint [id]="_hintLabelId">{{hintLabel}}</mat-hint>
}
}
<ng-content select="mat-hint:not([align='end'])"></ng-content>
<div class="mat-mdc-form-field-hint-spacer"></div>
<ng-content select="mat-hint[align='end']"></ng-content>
</div>
</div>
53 changes: 53 additions & 0 deletions src/material/form-field/form-field.ts
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,7 @@ export class MatFormField
this._stateChanges = control.stateChanges.subscribe(() => {
this._updateFocusState();
this._syncDescribedByIds();
this._showOrHideSubscript();
this._changeDetectorRef.markForCheck();
});

Expand Down Expand Up @@ -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();
}

Expand Down Expand Up @@ -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;
Expand All @@ -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
Expand Down
Loading