Overview for datepicker
The datepicker allows users to enter a date either through text input, or by choosing a date from the calendar. It is made up of several components, directives and the date implementation that work together.
Connecting a datepicker to an input
A datepicker is composed of a text input and a calendar pop-up, connected via the matDatepicker
property on the text input.
There is also an optional datepicker toggle button that gives the user an easy way to open the datepicker pop-up.
<input matInput [matDatepicker]="picker">
<mat-hint>MM/DD/YYYY</mat-hint>
<mat-datepicker-toggle matIconSuffix [for]="picker"></mat-datepicker-toggle>
<mat-datepicker #picker></mat-datepicker>
This works exactly the same with an input that is part of an <mat-form-field>
and the toggle
can easily be used as a prefix or suffix on the Material input:
<mat-form-field>
<mat-label>Choose a date</mat-label>
<input matInput [matDatepicker]="picker">
<mat-hint>MM/DD/YYYY</mat-hint>
<mat-datepicker-toggle matIconSuffix [for]="picker"></mat-datepicker-toggle>
<mat-datepicker #picker></mat-datepicker>
</mat-form-field>
If you want to customize the icon that is rendered inside the mat-datepicker-toggle
, you can do so
by using the matDatepickerToggleIcon
directive:
Date range selection
If you want your users to select a range of dates, instead of a single date, you can use the
mat-date-range-input
and mat-date-range-picker
components. They work in tandem, similarly to the
mat-datepicker
and the basic datepicker input.
The mat-date-range-input
component requires two input
elements for the start and end dates,
respectively:
<mat-date-range-input>
<input matStartDate placeholder="Start date">
<input matEndDate placeholder="End date">
</mat-date-range-input>
The mat-date-range-picker
component acts as the pop-up panel for selecting dates. This works in
the same way as mat-datepicker
, but allows the user to select multiple times:
<mat-date-range-picker #picker></mat-date-range-picker>
Connect the range picker and range input using the rangePicker
property:
<mat-date-range-input [rangePicker]="picker">
<input matStartDate placeholder="Start date">
<input matEndDate placeholder="End date">
</mat-date-range-input>
<mat-date-range-picker #picker></mat-date-range-picker>
Date range input forms integration
The mat-date-range-input
component can be used together with the FormGroup
directive from
@angular/forms
to group the start and end values together and to validate them as a group.
Selected range: { "start": null, "end": null }
Setting the calendar starting view
The startView
property of <mat-datepicker>
can be used to set the view that will show up when
the calendar first opens. It can be set to month
, year
, or multi-year
; by default it will open
to month view.
The month, year, or range of years that the calendar opens to is determined by first checking if any
date is currently selected, if so it will open to the month or year containing that date. Otherwise
it will open to the month or year containing today's date. This behavior can be overridden by using
the startAt
property of <mat-datepicker>
. In this case the calendar will open to the month or
year containing the startAt
date.
Watching the views for changes on selected years and months
When a year or a month is selected in multi-year
and year
views respectively, the yearSelected
and monthSelected
outputs emit a normalized date representing the chosen year or month. By
"normalized" we mean that the dates representing years will have their month set to January and
their day set to the 1st. Dates representing months will have their day set to the 1st of the
month. For example, if <mat-datepicker>
is configured to work with javascript native Date
objects, the yearSelected
will emit new Date(2017, 0, 1)
if the user selects 2017 in
multi-year
view. Similarly, monthSelected
will emit new Date(2017, 1, 1)
if the user
selects February in year
view and the current date value of the connected <input>
was
set to something like new Date(2017, MM, dd)
when the calendar was opened (the month and day are
irrelevant in this case).
Notice that the emitted value does not affect the current value in the connected <input>
, which
is only bound to the selection made in the month
view. So if the end user closes the calendar
after choosing a year in multi-view
mode (by pressing the ESC
key, for example), the selected
year, emitted by yearSelected
output, will not cause any change in the value of the date in the
associated <input>
.
The following example uses yearSelected
and monthSelected
outputs to emulate a month and year
picker (if you're not familiar with the usage of MomentDateAdapter
and MAT_DATE_FORMATS
you can read more about them below in
this document to fully understand the example).
Setting the selected date
The type of values that the datepicker expects depends on the type of DateAdapter
provided in your
application. The NativeDateAdapter
, for example, works directly with plain JavaScript Date
objects. When using the MomentDateAdapter
, however, the values will all be Moment.js instances.
This use of the adapter pattern allows the datepicker component to work with any arbitrary date
representation with a custom DateAdapter
.
See Choosing a date implementation
for more information.
Depending on the DateAdapter
being used, the datepicker may automatically deserialize certain date
formats for you as well. For example, both the NativeDateAdapter
and MomentDateAdapter
allow
ISO 8601 strings to be passed to the datepicker and
automatically converted to the proper object type. This can be convenient when binding data directly
from your backend to the datepicker. However, the datepicker will not accept date strings formatted
in user format such as "1/2/2017"
as this is ambiguous and will mean different things depending on
the locale of the browser running the code.
As with other types of <input>
, the datepicker works with @angular/forms
directives such as
formGroup
, formControl
, ngModel
, etc.
Date validation
There are three properties that add date validation to the datepicker input. The first two are the
min
and max
properties. In addition to enforcing validation on the input, these properties will
disable all dates on the calendar popup before or after the respective values and prevent the user
from advancing the calendar past the month
or year
(depending on current view) containing the
min
or max
date.
The second way to add date validation is using the matDatepickerFilter
property of the datepicker
input. This property accepts a function of <D> => boolean
(where <D>
is the date type used by
the datepicker, see
Choosing a date implementation).
A result of true
indicates that the date is valid and a result of false
indicates that it is
not. Again this will also disable the dates on the calendar that are invalid. However, one important
difference between using matDatepickerFilter
vs using min
or max
is that filtering out all
dates before or after a certain point, will not prevent the user from advancing the calendar past
that point.
In this example the user cannot select any date that falls on a Saturday or Sunday, but all of the dates which fall on other days of the week are selectable.
Each validation property has a different error that can be checked:
- A value that violates the
min
property will have amatDatepickerMin
error. - A value that violates the
max
property will have amatDatepickerMax
error. - A value that violates the
matDatepickerFilter
property will have amatDatepickerFilter
error.
Input and change events
The input's native (input)
and (change)
events will only trigger due to user interaction with
the input element; they will not fire when the user selects a date from the calendar popup.
Therefore, the datepicker input also has support for (dateInput)
and (dateChange)
events. These
trigger when the user interacts with either the input or the popup.
The (dateInput)
event will fire whenever the value changes due to the user typing or selecting a
date from the calendar. The (dateChange)
event will fire whenever the user finishes typing input
(on <input>
blur), or when the user chooses a date from the calendar.
Disabling parts of the datepicker
As with any standard <input>
, it is possible to disable the datepicker input by adding the
disabled
property. By default, the <mat-datepicker>
and <mat-datepicker-toggle>
will inherit
their disabled state from the <input>
, but this can be overridden by setting the disabled
property on the datepicker or toggle elements. This can be useful if you want to disable text input
but allow selection via the calendar or vice-versa.
Confirmation action buttons
By default, clicking on a date in the calendar will select it and close the calendar popup. In some
cases this may not be desirable, because the user doesn't have a quick way of going back if they've
changed their mind. If you want your users to be able to cancel their selection and to have to
explicitly accept the value that they've selected, you can add a <mat-datepicker-actions>
element
inside <mat-datepicker>
with a "Cancel" and an "Apply" button marked with the
matDatepickerCancel
and matDatepickerApply
attributes respectively. Doing so will cause the
datepicker to only assign the value to the data model if the user presses "Apply", whereas pressing
"Cancel" will close popup without changing the value.
<mat-datepicker #datepicker>
<mat-datepicker-actions>
<button mat-button matDatepickerCancel>Cancel</button>
<button mat-raised-button matDatepickerApply>Apply</button>
</mat-datepicker-actions>
</mat-datepicker>
The actions element is also supported for <mat-date-range-picker>
where that it is called
<mat-date-range-picker-actions>
and the buttons are called matDateRangePickerCancel
and
matDateRangePickerApply
respectively.
<mat-date-range-picker #rangePicker>
<mat-date-range-picker-actions>
<button mat-button matDateRangePickerCancel>Cancel</button>
<button mat-raised-button matDateRangePickerApply>Apply</button>
</mat-date-range-picker-actions>
</mat-date-range-picker>
Comparison ranges
If your users need to compare the date range that they're currently selecting with another range,
you can provide the comparison range start and end dates to the mat-date-range-input
using the
comparisonStart
and comparisonEnd
bindings. The comparison range will be rendered statically
within the calendar, but it will change colors to indicate which dates overlap with the user's
selected range. The comparison and overlap colors can be customized using the
datepicker-date-range-colors
mixin.
@use '@angular/material' as mat;
@include mat.datepicker-date-range-colors(hotpink, teal, yellow, purple);
Customizing the date selection logic
The mat-date-range-picker
supports custom behaviors for range previews and selection. To customize
this, you first create a class that implements MatDateRangeSelectionStrategy
, and then provide
the class via the MAT_DATE_RANGE_SELECTION_STRATEGY
injection token. The following example
uses the range selection strategy to create a custom range picker that limits the user to five-day
ranges.
Touch UI mode
The datepicker normally opens as a popup under the input. However this is not ideal for touch
devices that don't have as much screen real estate and need bigger click targets. For this reason
<mat-datepicker>
has a touchUi
property that can be set to true
in order to enable a more
touch friendly UI where the calendar opens in a large dialog.
Manually opening and closing the calendar
The calendar popup can be programmatically controlled using the open
and close
methods on the
<mat-datepicker>
. It also has an opened
property that reflects the status of the popup.
Using mat-calendar
inline
If you want to allow the user to select a date from a calendar that is inlined on the page rather
than contained in a popup, you can use <mat-calendar>
directly. The calendar's height is
determined automatically based on the width and the number of dates that need to be shown for a
month. If you want to make the calendar larger or smaller, adjust the width rather than the height.
Sunday | Monday | Tuesday | Wednesday | Thursday | Friday | Saturday |
---|---|---|---|---|---|---|
FEB | ||||||
Selected date:
Internationalization
Internationalization of the datepicker is configured via four aspects:
- The date locale.
- The date implementation that the datepicker accepts.
- The display and parse formats used by the datepicker.
- The message strings used in the datepicker's UI.
Setting the locale code
By default, the MAT_DATE_LOCALE
injection token will use the existing LOCALE_ID
locale code
from @angular/core
. If you want to override it, you can provide a new value for the
MAT_DATE_LOCALE
token:
bootstapApplication(MyApp, {
providers: [{provide: MAT_DATE_LOCALE, useValue: 'en-GB'}],
});
It's also possible to set the locale at runtime using the setLocale
method of the DateAdapter
.
Note: if you're using the provideDateFnsAdapter
, you have to provide the data object for your
locale to MAT_DATE_LOCALE
instead of the locale code, in addition to providing a configuration
compatible with date-fns
to MAT_DATE_FORMATS
. Locale data for date-fns
can be imported
from date-fns/locale
.
Choosing a date implementation and date format settings
The datepicker was built to be date implementation agnostic. This means that it can be made to work with a variety of different date implementations. However it also means that developers need to make sure to provide the appropriate pieces for the datepicker to work with their chosen implementation.
The easiest way to ensure this is to import one of the provided date adapters:
provideNativeDateAdapter
or MatNativeDateModule
Date type | Date |
---|---|
Supported locales | en-US |
Dependencies | None |
Import from | @angular/material/core |
provideDateFnsAdapter
or MatDateFnsModule
(installed via ng add @angular/material-date-fns-adapter
)
Date type | Date |
---|---|
Supported locales | See project for details |
Dependencies | date-fns |
Import from | @angular/material-date-fns-adapter |
provideLuxonDateAdapter
or MatLuxonDateModule
(installed via ng add @angular/material-luxon-adapter
)
Date type | DateTime |
---|---|
Supported locales | See project for details |
Dependencies | Luxon |
Import from | @angular/material-luxon-adapter |
provideMomentDateAdapter
or MatMomentDateModule
(installed via ng add @angular/material-moment-adapter
)
Date type | Moment |
---|---|
Supported locales | See project for details |
Dependencies | Moment.js |
Import from | @angular/material-moment-adapter |
Please note: provideNativeDateAdapter
is based off the functionality available in JavaScript's
native Date
object.
Thus it is not suitable for many locales. One of the biggest shortcomings of the native Date
object is the inability to set the parse format. We strongly recommend using an adapter based on
a more robust formatting and parsing library. You can use provideMomentDateAdapter
or a custom DateAdapter
that works with the library of your choice.
These APIs include providers for DateAdapter
and MAT_DATE_FORMATS
.
bootstrapApplication(MyApp, {
providers: [provideNativeDateAdapter()]
});
Because DateAdapter
is a generic class, MatDatepicker
and MatDatepickerInput
also need to be
made generic. When working with these classes (for example as a ViewChild
) you should include the
appropriate generic type that corresponds to the DateAdapter
implementation you are using. For
example:
@Component({...})
export class MyComponent {
@ViewChild(MatDatepicker) datepicker: MatDatepicker<Date>;
}
By default the MomentDateAdapter
creates dates in your time zone specific locale. You can change
the default behaviour to parse dates as UTC by passing useUtc: true
into provideMomentDateAdapter
or by providing the MAT_MOMENT_DATE_ADAPTER_OPTIONS
injection token.
bootstrapApplication(MyApp, {
providers: [provideMomentDateAdapter(undefined, {useUtc: true})]
});
By default the MomentDateAdapter
will parse dates in a
forgiving way. This may result in dates
being parsed incorrectly. You can change the default behaviour to
parse dates strictly by strict: true
to
provideMomentDateAdapter
or by providing the MAT_MOMENT_DATE_ADAPTER_OPTIONS
injection token.
bootstrapApplication(MyApp, {
providers: [provideMomentDateAdapter(undefined, {strict: true})]
});
It is also possible to create your own DateAdapter
that works with any date format your app
requires. This is accomplished by subclassing DateAdapter
and providing your subclass as the
DateAdapter
implementation. You will also want to make sure that the MAT_DATE_FORMATS
provided
in your app are formats that can be understood by your date implementation. See
Customizing the parse and display formats for more
information about MAT_DATE_FORMATS
.
bootstrapApplication(MyApp, {
providers: [
{provide: DateAdapter, useClass: MyDateAdapter},
{provide: MAT_DATE_FORMATS, useValue: MY_DATE_FORMATS},
]
});
If you need to work with native Date
objects, but need custom behavior (for example custom date
parsing), you can consider subclassing NativeDateAdapter
.
Customizing the parse and display formats
The MAT_DATE_FORMATS
object is a collection of formats that the datepicker uses when parsing
and displaying dates. These formats are passed through to the DateAdapter
so you will want to make
sure that the format objects you're using are compatible with the DateAdapter
used in your app.
If you want use one of the DateAdapters
that ships with Angular Material, but use your own
MAT_DATE_FORMATS
, you can either pass the formats into the providers function, or provide the
MAT_DATE_FORMATS
token yourself. For example:
bootstrapApplication(MyApp, {
providers: [provideNativeDateAdapter(MY_NATIVE_DATE_FORMATS)],
});
Moment.js formats
To use custom formats with the provideMomentDateAdapter
you can pick from the parse formats
documented here and the display formats
documented here.
It is also possible to support multiple parse formats. For example:
bootstraApplication(MyApp, {
providers: [provideMomentDateAdapter({
parse: {
dateInput: ['l', 'LL'],
},
display: {
dateInput: 'L',
monthYearLabel: 'MMM YYYY',
dateA11yLabel: 'LL',
monthYearA11yLabel: 'MMMM YYYY',
},
})]
});
Customizing the calendar header
The header section of the calendar (the part containing the view switcher and previous and next
buttons) can be replaced with a custom component if desired. This is accomplished using the
calendarHeaderComponent
property of <mat-datepicker>
. It takes a component class and constructs
an instance of the component to use as the header.
In order to interact with the calendar in your custom header component, you can inject the parent
MatCalendar
in the constructor. To make sure your header stays in sync with the calendar,
subscribe to the stateChanges
observable of the calendar and mark your header component for change
detection.
Localizing labels and messages
The various text strings used by the datepicker are provided through MatDatepickerIntl
.
Localization of these messages can be done by providing a subclass with translated values in your
app config.
bootstrapApplication(MyApp, {
providers: [
{provide: MatDatepickerIntl, useClass: MyIntl},
provideNativeDateAdapter(),
],
});
Highlighting specific dates
If you want to apply one or more CSS classes to some dates in the calendar (e.g. to highlight a
holiday), you can do so with the dateClass
input. It accepts a function which will be called
with each of the dates in the calendar and will apply any classes that are returned. The return
value can be anything that is accepted by ngClass
.
Accessibility
The MatDatepicker
pop-up uses the role="dialog"
interaction pattern. This dialog then contains
multiple controls, the most prominent being the calendar itself. This calendar implements the
role="grid"
interaction pattern.
Always enable confirmation action buttons. This allows assistive technology users to explicitly confirm their selection before committing a value.
The MatDatepickerInput
and MatDatepickerToggle
directives both apply the aria-haspopup
attribute to the native input and button elements, respectively.
MatDatepickerIntl
includes strings that are used for aria-label
attributes. Always provide
the datepicker text input a meaningful label via <mat-label>
, aria-label
, aria-labelledby
or
MatDatepickerIntl
.
Always communicate the date format (e.g. 'MM/DD/YYYY'). This can be accomplished using <mat-hint>
or by providing an additional label adjacent to the form field.
MatDatepickerInput
adds >Alt + Down Arrow as a keyboard short to open the
datepicker pop-up. However, ChromeOS intercepts this key combination at the OS level such that the
browser only receives a PageDown
key event. Because of this behavior, you should always include an
additional means of opening the pop-up, such as MatDatepickerToggle
.
MatDatepickerToggle
must be included along with MatDatepicker
for optimal mobile a11y
compatibility. Mobile screen reader users currently do not have a way to trigger the datepicker
dialog without the icon button present.
Keyboard interaction
The datepicker supports the following keyboard shortcuts:
Keyboard Shortcut | Action |
---|---|
Alt + Down Arrow | Open the calendar pop-up |
Escape | Close the calendar pop-up |
In month view:
Shortcut | Action |
---|---|
Left Arrow | Go to previous day |
Right Arrow | Go to next day |
Up Arrow | Go to same day in the previous week |
Down Arrow | Go to same day in the next week |
Home | Go to the first day of the month |
End | Go to the last day of the month |
Page up | Go to the same day in the previous month |
Alt + Page up | Go to the same day in the previous year |
Page Down | Go to the same day in the next month |
Alt + Page Down | Go to the same day in the next year |
Enter | Select current date |
In year view:
Shortcut | Action |
---|---|
Left Arrow | Go to previous month |
Right Arrow | Go to next month |
Up Arrow | Go up a row (back 4 months) |
Down Arrow | Go down a row (forward 4 months) |
Home | Go to the first month of the year |
End | Go to the last month of the year |
Page Up | Go to the same month in the previous year |
Alt + Page up | Go to the same month 10 years back |
Page Down | Go to the same month in the next year |
Alt + Page Down | Go to the same month 10 years forward |
Enter | Select current month |
In multi-year view:
Shortcut | Action |
---|---|
Left Arrow | Go to previous year |
Right Arrow | Go to next year |
Up Arrow | Go up a row (back 4 years) |
Down Arrow | Go down a row (forward 4 years) |
Home | Go to the first year in the current range |
End | Go to the last year in the current range |
Page up | Go back 24 years |
Alt + Page up | Go back 240 years |
Page Down | Go forward 24 years |
Alt + Page Down | Go forward 240 years |
Enter | Select current year |
Troubleshooting
Error: MatDatepicker: No provider found for DateAdapter/MAT_DATE_FORMATS
This error is thrown if you have not provided all of the injectables the datepicker needs to work.
The easiest way to resolve this is to add provideNativeDateAdapter
or provideMomentDateAdapter
to your app config. See
Choosing a date implementation) for
more information.
Error: A MatDatepicker can only be associated with a single input
This error is thrown if more than one <input>
tries to claim ownership over the same
<mat-datepicker>
(via the matDatepicker
attribute on the input). A datepicker can only be
associated with a single input.
Error: Attempted to open an MatDatepicker with no associated input.
This error occurs if your <mat-datepicker>
is not associated with any <input>
. To associate an
input with your datepicker, create a template reference for the datepicker and assign it to the
matDatepicker
attribute on the input:
<input [matDatepicker]="picker">
<mat-datepicker #picker></mat-datepicker>