-
Notifications
You must be signed in to change notification settings - Fork 6.7k
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/datepicker): add aria labels to <input/>
s for Start/En…
#24949
Conversation
f417783
to
ba2f2c8
Compare
Deployed dev-app to: https://ng-comp-dev--pr-24949-13434c5536a22c070e071137a9ad0281-dltkcrvm.web.app |
constructor( | ||
private _elementRef: ElementRef<HTMLElement>, | ||
private _ngZone: NgZone, | ||
private _intl: MatDatepickerIntl, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since the calendar body is exposed as a public API, this will have to be marked as optional initially. Here's an example of how it should be done: https://github.com/angular/components/blob/main/src/cdk/table/table.ts#L518
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or just use the new inject()
style? I think that's probably what we want to start doing. As a reference, see #24941
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, I made it optional. (This commit is on another PR, #24950).
Would switching all of Datepicker to the new inject()
style be considered a breaking change?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not necessarily, but the shape of the constructor would have to stay the same. You can try changing it to something like:
constructor(...args: any[]) {}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, I used inject()
to add the MatDatepickerIntl
dependency in a non-breaking way. No changes to the constructor are required.
@@ -392,6 +394,16 @@ export class MatDateRangeInput<D> | |||
this.stateChanges.next(); | |||
} | |||
|
|||
/** Gets the value for the aria label for the start date input. */ | |||
_getStartDateLabel() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if it wouldn't make more sense for the start/end date labels to be configurable either on mat-date-range-input
or on matStartDate
/matEndDate
, instead of through MatDatepickerIntl
. The problem with having it be in the provider is that it affects all range inputs in the app, but they may represent different things. E.g. in a travel site the flights search might say "Departure" and "Return" while the hotel search would say "Check in" and "Check out".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's good point, didn't think of that. MatDatepickerIntl
is injectable, so if there were a Flights pages and a Hotel pages in the same app. The Flight page could inject "Departure"/"Arrival" and the hotel page could inject "Check in"/"Check out". It seems like we have this case covered, but I should definitely add a unit test for that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are other cases where this wouldn't work though. Like if you had two different range inputs on the same page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I still don't get it; I think I might not be understanding how DI works. If there were two different range inputs rendered by two different components, couldn't the two inject their own values for "Start Date"/"End Date"?
Something like injecting either HotelMatDatepickerIntl
or AirlineMatDatepickerIntl
depending on the need.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think it would be necessary to make the labels configurable on mat-date-range-input
or on matStartDate/matEndDate, instead of through MatDatepickerIntl.
On the one hand, it makes sense for developers to be able to able to set the descriptions for each individual inputs. On the other hand, we would also need a way to specify an aria-description on the calendar pop-up for date ranges of length 1, where the start date and end date are on the same day (e.g. "Start and end date"). In general, is there a requirement for how customizable the matStartDate
/matEndDate
are?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The problem with doing it through DI is if you have more than one date range input in the same component. E.g.
@Component({
providers: [{provide: MatDatepickerIntl, useClass: CustomDatepickerIntl}],
template: `
<mat-date-range-input></mat-date-range-input>
<mat-date-range-input></mat-date-range-input>
`
})
class Comp {}
In this case both range inputs will end up with the same descriptions, even though they might not represent the same values.
31909cc
to
134a4d8
Compare
…d Date Give `matDateStart` aria label of "Start Date" and give `matDateEnd` a label of "End Date" by wrapping in a `<label>` element. Apply the aria label of the form field to the `<mat-date-range-input>` component, which has role of group. Previously the placeholder was used to communicate which of the inputs was the start date and which was the end date. Only affects the DOM structure and a11y tree. Does not change the visual appearance. Consider the [Basic date range picker example](https://material.angular.io/components/datepicker/overview#date-range-picker-overview): ``` <mat-form-field appearance="fill"> <mat-label>Enter a date range</mat-label> <mat-date-range-input [rangePicker]="picker"> <input matStartDate placeholder="Start date"> <input matEndDate placeholder="End date"> </mat-date-range-input> ... </mat-form-field> ``` Previously, it would produce an accessibility tree that looks something like this. ``` group "Enter a date range" LabelText StaticText "Enter a date range" textbox "Enter a date range" Textbox "End date" ``` Problems with this approach. 1. Screen reader does not announce "Start Date" right away or not at 2. "Start date"/"End date" come from the placeholder put a label would be more appropriate. With this commit applied, accessibility is consistent between both inputs, and it is easier to tell which of the two is the start and which is the end. ``` group "Enter a date range" LabelText textbox "Start Date" LabelText textbox "End Date" ``` Fixes: angular#23445
134a4d8
to
13434c5
Compare
The discussion on |
This issue has been automatically locked due to inactivity. Read more about our automatic conversation locking policy. This action has been performed automatically by a bot. |
Description
Give
matDateStart
aria label of "Start Date" and givematDateEnd
a label of "End Date" by wrapping in a
<label>
element. Apply the arialabel of the form field to the
<mat-date-range-input>
component, whichhas role of group. Previously the placeholder was used to communicate
which of the inputs was the start date and which was the end date.
Only affects the DOM structure and a11y tree. Does not change the visual appearance.
Consider the Basic date range picker
example:
Previously, it would produce an accessibility tree that looks something
like this.
Problems with this approach.
be more appropriate.
With this commit applied, accessibility is consistent between both
inputs, and it is easier to tell which of the two is the start and which
is the end.
Fixes: #23445
Note to reviewers
The first commit can be ignored as it is from another PR