Date Picker
- Usage
- Styling
Date Picker is an input field that allows the user to enter a date by typing or by selecting from a calendar overlay.
Try clicking the calendar icon. A calendar overlay appears, showing the current month. Click on a date to select it.
The date can be entered directly using the keyboard in the format of the current locale or through the date picker overlay. The overlay opens when the field is clicked or any input is entered when the field is focused.
Date Format
Date Picker can be configured to display dates and parse user input in a specific format.
Using Java Locales (Java Only)
By default, Date Picker displays and parses dates using the user’s locale (reference). Alternatively, setting a specific locale ensures that all users consistently see the same format. In the example here, the Date Picker is set to the date format used in Finland.
new tab
Locale finnishLocale = new Locale("fi", "FI");
DatePicker datePicker = new DatePicker("Select a date:");
datePicker.setLocale(finnishLocale);
The date format that’s used based on the locale depends on the specific browser implementation and might not be reliable when expecting a specific pattern. For finer control over the date format, see the next section.
Using Custom Date Formats (Java Only)
Date Picker allows you to configure a custom date format pattern that defines exactly how dates should be displayed and how user input should be parsed. Additional parsing formats can be provided to support entering dates in different formats. Parsing is first tried with the primary format, then by additional parsing formats in the order that they are provided.
new tab
// Setup date picker with a single custom format `yyyy-MM-dd` for
// displaying dates and parsing user input
// Custom date formats are specified using the date pickers
// internationalization API
DatePicker.DatePickerI18n singleFormatI18n = new DatePicker.DatePickerI18n();
singleFormatI18n.setDateFormat("yyyy-MM-dd");
DatePicker singleFormatDatePicker = new DatePicker("Select a date:");
singleFormatDatePicker.setI18n(singleFormatI18n);
// Setup date picker with a primary format and additional parsing
// formats
// Date is always displayed using the primary format `yyyy-MM-dd`
// When parsing user input, the date picker first attempts to match the
// input with the primary format `yyyy-MM-dd`, then `MM/dd/yyyy`, and
// finally `dd.MM.yyyy`
DatePicker.DatePickerI18n multiFormatI18n = new DatePicker.DatePickerI18n();
multiFormatI18n.setDateFormats("yyyy-MM-dd", "MM/dd/yyyy",
"dd.MM.yyyy");
DatePicker multiFormatDatePicker = new DatePicker("Select a date:");
multiFormatDatePicker.setI18n(multiFormatI18n);
A custom date format pattern is a string that consists of specific symbols that specify how and where a part of the date (i.e., day, month, or year) should be displayed. The following symbols are recognized as parts of the date in a pattern:
Code | Description |
---|---|
| Day of the month, as one or two digits (e.g., 1, 31). |
| Day of the month, padded to two digits (e.g., 01, 31). |
| Month, as one or two digits (e.g., 1, 12). |
| Month, padded to two digits (e.g., 01, 12). |
| Year, using two digits (e.g., 23). |
| Year, using four digits (e.g., 2023). |
Other characters, such as separators (e.g., /
, .
, -
) or spaces may be used in a pattern.
Below are some examples of how you might use these date format codes:
Pattern | Example Value | Description |
---|---|---|
|
| United States date format. |
|
| ISO 8601 date format. |
|
| Croatian date format using spaces. |
|
| Date format using only day and month. |
Custom date patterns take precedence over the configured locale. When using both at the same time, the custom date pattern is used to display and parse dates.
Two-Digit Year Formats
Date Picker supports date formats with 2-digit years (e.g., dd.MM.yy
). When parsing a 2-digit year, the component must decide as to which century to parse the year. For example, a year entered as 62
could be interpreted either as 1862, 1962, or 2062.
Two-digit years are interpreted as being within a 100-year range whose midpoint is called the reference date. For example, a reference date of 2000-01-01 means that the date entered is interpreted as being within the range 1950-01-01 to 2049-12-31. Given that parameter, the year 50
is parsed to 1950 while 49
is parsed to 2049.
The reference date defaults to the current date, but you can set it to a different date with the internationalization API:
DatePicker.DatePickerI18n i18n = new DatePicker.DatePickerI18n();
i18n.setDateFormat("yy-MM-dd");
i18n.setReferenceDate(LocalDate.of(1980, 2, 2));
datePicker.setI18n(i18n);
When using a display format with a 4-digit year, years prior to 1000 are displayed padded with leading zeroes to avoid ambiguity.
Note
|
Display formats with 2-digit years should only be used with 2-digit parsing formats. Using a display format with 2-digit years (yy ), together with parsing formats with 4-digit years (yyyy ) can cause unexpected behavior, and should be avoided.
|
Using Custom Functions (Client-Side Only)
When using the web component stand-alone, custom functions can be configured to display and parse the date.
new tab
protected override firstUpdated() {
const formatDateIso8601 = (dateParts: DatePickerDate): string => {
const { year, month, day } = dateParts;
const date = new Date(year, month, day);
return dateFnsFormat(date, 'yyyy-MM-dd');
};
const parseDateIso8601 = (inputValue: string): DatePickerDate => {
const date = dateFnsParse(inputValue, 'yyyy-MM-dd', new Date());
return { year: date.getFullYear(), month: date.getMonth(), day: date.getDate() };
};
this.datePicker.i18n = {
...this.datePicker.i18n,
formatDate: formatDateIso8601,
parseDate: parseDateIso8601,
};
}
The previous example uses the third-party library date-fns to implement the custom formatting and parsing functions. It needs to be added as a separate dependency to the project.
Validation
To validate a date entered or selected, various ways may be used. For instance, you may want to allow only dates in a certain range, or you might not want to allow certain dates. Below are some of your options for date validation.
Min & Max Value
The valid input range of Date Picker can be restricted by defining min
and max
values. Dates before the min
and after the max
are disabled in the overlay. Helper text can be used to inform the user about the accepted range.
new tab
<vaadin-date-picker
label="Appointment date"
helper-text="Must be within 60 days from today"
.min="${formatISO(this.minDate, { representation: 'date' })}"
.max="${formatISO(this.maxDate, { representation: 'date' })}"
.errorMessage="${this.errorMessage}"
@change="${({ target }: DatePickerChangeEvent) => {
const date = dateFnsParse(target.value ?? '', 'yyyy-MM-dd', new Date());
if (isBefore(date, this.minDate)) {
this.errorMessage = 'Too early, choose another date';
} else if (isAfter(date, this.maxDate)) {
this.errorMessage = 'Too late, choose another date';
} else {
this.errorMessage = '';
}
}}"
></vaadin-date-picker>
Custom Validation
Date Picker supports custom validation, such as limiting the options to Monday through Friday. In the following example, select a date that’s on a Sunday or a Saturday to see a custom validation message.
new tab
private binder = new Binder(this, AppointmentModel);
protected override firstUpdated() {
this.binder.for(this.binder.model.startDate).addValidator({
message: 'Select a weekday',
validate: (startDate: string) => {
const date = new Date(startDate);
const isWeekday = date.getDay() >= 1 && date.getDay() <= 5;
return isWeekday;
},
});
}
protected override render() {
return html`
<vaadin-date-picker
label="Meeting date"
helper-text="Mondays – Fridays only"
${field(this.binder.model.startDate)}
></vaadin-date-picker>
`;
}
Week Numbers
Week numbers (ISO-8601) can be enabled in the calendar overlay. This works only when the first day of the week is set to Monday.
new tab
protected override firstUpdated() {
this.datePicker.i18n = {
...this.datePicker.i18n,
firstDayOfWeek: 1,
};
}
protected override render() {
return html`
<vaadin-date-picker label="Vacation start date" show-week-numbers></vaadin-date-picker>
`;
}
Initial Position
Date Picker’s initial position parameter defines which date is focused in the calendar overlay when the overlay is opened. The default, initial position is the selected or current date.
Use this feature to minimize the need for unnecessary navigation or scrolling when the user’s input is expected to be within a certain time. In the following example, click the Date Picker to open the calendar overlay and notice that the highlighted, focused date is in the future (i.e., the last day of the year), instead of the current date.
new tab
<vaadin-date-picker
label="Q4 deadline"
.initialPosition="${formatISO(this.lastDayOfTheYear, { representation: 'date' })}"
></vaadin-date-picker>
Auto Open
The overlay automatically opens when the field is focused with a click or a tap, and when typing a value in the input. This can be prevented to have the overlay only open when the toggle button or the up/down arrow keys are pressed. This behavior isn’t affected, though, on touch devices.
Internationalization (i18n)
Date Picker allows localizing text and labels, such as month names and button labels.
new tab
@query('vaadin-date-picker')
private accessor datePicker!: DatePicker;
protected override firstUpdated() {
this.datePicker.i18n = {
...this.datePicker.i18n,
monthNames: [
'Januar',
'Februar',
'März',
'April',
'Mai',
'Juni',
'Juli',
'August',
'September',
'Oktober',
'November',
'Dezember',
],
weekdays: ['Sonntag', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag'],
weekdaysShort: ['So', 'Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa'],
today: 'Heute',
cancel: 'Abbrechen',
};
}
protected override render() {
return html`<vaadin-date-picker label="Sitzungsdatum"></vaadin-date-picker>`;
}
See also how to configure a custom date format.
Basic Features
The following features, common to most input field components, are supported:
Label
The label is used to identify the input field. It supports plain-text content, and its length is limited to the width of the field. Helpers and Tooltips can be used to provide additional information that doesn’t fit into the label.
Visible labels are strongly recommended for all input fields. In cases where the built-in label cannot be used, an external element can be associated as the field’s label through the aria-labelledby
attribute. Fields without any visible label should include an invisible label for assistive technologies with the aria-label
attribute.
Helper
Helpers are used to provide additional information that the user may need to enter in the field, such as format requirements or explanations of the field’s purpose below the field.
A style variant is available for rendering the helper above the field.
In addition to plain text, helpers can contain components and HTML elements. However, complex and interactive content is likely to have accessibility issues.
Placeholder
The placeholder is text that’s displayed when the field is empty. Its primary purpose is to provide a short input hint (e.g., the expected format) in situations where a Helper cannot be used.
Placeholders should not be used as a replacement for a visible label. They can be mistaken for a manually entered value. See Label for alternatives to the built-in field label.
Tooltip
Tooltips are small text pop-ups displayed on hover, and on keyboard-focus. They can be used to provide additional information about a field. This can be useful in situations where an always visible Helper is not appropriate. Helpers are generally recommended in favor of tooltips, though, as they provide much better discoverability and mobile support. See the Tooltip documentation for more information.
Prefix
A prefix element — rendered at the start of the field — can be used to display units, icons, and similar visual cues to the field’s purpose or format.
External & Invisible Labels (ARIA)
Visible labels are strongly recommended for all input fields. In situations where the built-in label cannot be used, an external element can be associated as the field’s label through its element id
. Fields without any visible label should be provided an invisible label for assistive technologies like screen readers.
<!-- Associates external element as label: -->
<label id="external-label">This is the label</label>
<vaadin-date-picker accessible-name-ref="external-label">...
<!-- Invisible label for screen readers: -->
<vaadin-date-picker accessible-name="This is the label">...
new tab
<vaadin-date-picker
label="Label"
helper-text="Helper text"
placeholder="Placeholder"
clear-button-visible
>
<vaadin-tooltip slot="tooltip" text="Tooltip text"></vaadin-tooltip>
<vaadin-icon slot="prefix" icon="vaadin:vaadin-h"></vaadin-icon>
</vaadin-date-picker>
Read-Only & Disabled
Fields used to display values should be set to read-only
mode to prevent editing. Read-only fields are focusable and visible to screen readers. They can display tooltips. Their values can be selected and copied.
Fields that are currently unavailable should be disabled
. The reduced contrast of disabled fields makes them inappropriate for displaying information. They can’t be focused or display tooltips. They’re invisible to screen readers, and their values cannot be selected and copied.
Disabled fields can be useful in situations where they can become enabled based on some user action. Consider hiding fields entirely if there’s nothing the user can do to make them editable.
new tab
<vaadin-date-picker readonly label="Read-only" value="2020-06-12"></vaadin-date-picker>
<vaadin-date-picker disabled label="Disabled"></vaadin-date-picker>
Style Variants
The following style variants can be applied:
Text Alignment
Three different text alignments are supported: left
, which is the default; center
; and right
.
Right-alignment is recommended for numerical values when presented in vertical groups. This tends to aid interpretation and comparison of values.
Small Variant
The small variant can be used to make individual fields more compact. The default size of fields can be customized with style properties.
Helper Above Field
The helper can be rendered above the field, and below the label.
Borders
Borders can be applied to the field surface by providing a value (e.g., 1px
) to the --vaadin-input-field-border-width
CSS property. This can be applied globally to all input fields using the html
selector, or to individual component instances. Borders are required to achieve WCAG 2.1 level AA conformant color contrast with the default Lumo styling of fields.
You can override the default border color with the --vaadin-input-field-border-color
property.
new tab
<vaadin-date-picker
theme="align-right small helper-above-field"
label="Label"
helper-text="Helper text"
value="2020-06-12"
style="--vaadin-input-field-border-width: 1px;"
></vaadin-date-picker>
Usage Patterns
Date Range
You can create a date range picker using the Date Picker twice. Imagine the following example is for an airline ticket booking page. It’s asking the user for the date they want to depart and when they want to return. Try it: select a departure date, and then proceed to select a return date. Notice how dates prior to the departure date you chose are now disabled.
new tab
<vaadin-horizontal-layout theme="spacing">
<vaadin-date-picker
label="Departure date"
.max="${this.returnDate}"
@value-changed="${(event: DatePickerValueChangedEvent) => {
this.departureDate = event.detail.value;
}}"
></vaadin-date-picker>
<vaadin-date-picker
label="Return date"
.min="${this.departureDate}"
@value-changed="${(event: DatePickerValueChangedEvent) => {
this.returnDate = event.detail.value;
}}"
></vaadin-date-picker>
</vaadin-horizontal-layout>
To disable the days before the start date in the end date picker, you need to handle the selection in the start date picker and change the range in the end date picker.
Best Practices
Picking vs. Typing
The calendar overlay is useful when the user needs to choose a day that’s close to the current date or when information such as day of the week, week number, valid dates, and so on can aid in choosing the best option.
For far off dates (i.e., years ago or years from now) and for known dates (i.e., holidays and birthdays), typing the date in the input field can be faster and easier. Because of this, it’s important to verify that the user can enter dates according to their locale.
Instead of a Date Picker, you can use individual input fields (i.e., day, month, and year) to improve usability on small touch devices. In the following example, focus the year field and start to type a year. As you enter each digit, notice the list of choices narrows.
new tab
@state()
accessor selectedYear: number | undefined;
@state()
accessor selectedMonth: string | undefined;
@state()
accessor selectedDay: number | undefined;
@state()
accessor selectableDays: number[] = [];
private handleYearChange(e: ComboBoxSelectedItemChangedEvent<number>) {
this.selectedYear = e.detail.value!;
this.selectedMonth = undefined;
this.selectedDay = undefined;
this.selectableDays = [];
}
private handleMonthChange(e: ComboBoxSelectedItemChangedEvent<string>) {
this.selectedMonth = e.detail.value!;
this.selectedDay = undefined;
if (!this.selectedYear || !this.selectedMonth) {
this.selectableDays = [];
return;
}
const startOfMonth = new Date(this.selectedYear, this.months.indexOf(this.selectedMonth), 1);
const lengthOfMonth = getDaysInMonth(startOfMonth);
this.selectableDays = Array.from({ length: lengthOfMonth }, (_, k) => k + 1);
}
private handleDayChange(e: ComboBoxSelectedItemChangedEvent<number>) {
this.selectedDay = e.detail.value!;
}
protected override render() {
return html`
<vaadin-horizontal-layout theme="spacing">
<vaadin-combo-box
label="Year"
style="width: 6em;"
.items="${this.years}"
.selectedItem="${this.selectedYear}"
@selected-item-changed="${this.handleYearChange}"
></vaadin-combo-box>
<vaadin-combo-box
label="Month"
style="width: 9em;"
.items="${this.months}"
.selectedItem="${this.selectedMonth}"
.disabled="${!this.selectedYear}"
@selected-item-changed="${this.handleMonthChange}"
></vaadin-combo-box>
<vaadin-combo-box
label="Day"
style="width: 5em;"
.items="${this.selectableDays}"
.selectedItem="${this.selectedDay}"
.disabled="${!this.selectedYear || !this.selectedMonth}"
@selected-item-changed="${this.handleDayChange}"
></vaadin-combo-box>
</vaadin-horizontal-layout>
`;
}
Note
|
Not Production-Ready
The previous example is only a prototype implementation to demonstrate the concept. It isn’t ready for production use.
|
Show the Date Format
Use a placeholder or helper to show how the input should be formatted. For example, "12/6/2020" represents different dates for Americans and Europeans. For most Americans, it’s a date in December. For many Europeans, it’s a date in June.
new tab
<vaadin-date-picker
label="Start date"
placeholder="DD/MM/YYYY"
helper-text="Format: DD/MM/YYYY"
></vaadin-date-picker>
Helpers are preferable to placeholders, as they’re always visible. Fields with placeholders are also less noticeable than empty fields, so they are susceptible to being skipped. Use placeholders when space is limited, for example when Date Picker is used as a filter in a data grid header.
Related Components
Component | Usage Recommendation |
---|---|
Input field for entering or selecting a specific time. | |
Input field for selecting both a date and a time. |
26595CB7-1A81-4EE1-B94C-948E889C3027