The datepicker
input allows users to select a date from a customizable calendar, and type the date directly into the input with full internationalization support.
FormKit uses a unique masking solution to allow users to type dates into the datepicker input (while limiting the available options to only valid values) or select their date via a calendar input.
To show a placeholder when in dual entry mode, you must enable the mask overlay
. This is not necessary with picker-only
enabled. Learn more about masks and overlays here.
You can disable the text-entry mechanism and ensure someone uses the datepicker dialog to enter their date by adding the picker-only
prop. In picker-only
mode, clicking on the input will open the dialog immediately. Additionally, using an overlay
is not required for placeholder support:
The datepicker supports Intl.DateTimeFormat
"styled dates", as well as token-based date formats. To change the format displayed to the user, modify the format
prop.
If your audience is international, you should consider sticking with "styled dates" since they are the most natural date formats in each locale. The default format for a datepicker is long
.
The format
prop can accept a simple string like long
or medium
, in which case it uses the corresponding Intl.DateTimeFormat
dateStyle
. Alternatively, you can provide an object with date
and time
properties and their respective Intl.DateTimeFormat
styles ({ date: 'long', time: 'short' }
).
Enable any of the following date styles with the format
prop:
Format Style | Examples |
---|---|
full | Wednesday, March 1, 2023 , Mercoledì 1 marzo 2023 |
long | March 1, 2023 , 1 marzo 2023 |
medium | Mar 6, 2023 , 6 mar 2023 |
short | 3/1/23 , 1/3/23 |
Format style | Examples |
---|---|
long | 7:05:00 PM , 19:05:00 |
medium | 7:05:00 PM , 19:05:00 |
short | 7:05 PM , 19:05 |
You can use the format
prop to explicitly set a tokenized date format. A token format is represented by a string with any arbitrary characters and one or more of the strings in the table below.
FormKit interfaces with the Intl.DateTimeFormat
to automatically internationalize tokens based on the current locale
. For example, the token MMMM
for 2000-01-01
would produce January
for the en
locale but would produce 一月
for the zh
locale.
It is possible, when using tokens, to create non-parsable dates. For example, if your input only displays the day of the week (dddd
). You can use non-parsable date formats only in picker-only
mode. If you’d like to allow your users to type in their date, your format must include at least a month, day, and year token.
Token | Examples | Description |
---|---|---|
YY | 99 , 23 , 00 | 2 digit year |
YYYY | 1999 , 2023 , 2100 | 4 digit year |
M | 1 , 12 | The month 1-12 |
MM | 01 , 12 | The month 01-12 |
MMM | Jan , Feb | Short name Jan-Dec |
MMMM | January , February | Full name January - December |
D | 1 , 9 , 22 | The day of the month 1-31 |
DD | 01 , 09 , 22 | The day of the month 01-31 |
d | M , T , W , T , F , S , S | Single digit day "T" |
ddd | Thu , Sat | Short day name "Thu" |
dddd | Monday , Tuesday | Full day name "Wednesday" |
H | 0 , 13 , 23 | Minimum hour digits, 24 hour, 0-23 |
HH | 00 , 13 , 23 | 2 hour digits, 24 hour, 00-23 |
h | 12 , 1 , 11 | Minimum hour digits, 12 hour clock, 1-12 |
hh | 12 , 01 , 11 | 2 hour digits, 12 hour clock, 01-12 |
m | 1 , 59 | The minute 0-59 |
mm | 01 , 59 | The minute 00-59 |
s | 1 , 59 | The second 0-59 |
ss | 01 , 59 | The second 00-59 |
a | am , pm | am/pm |
A | AM , PM | AM/PM |
Although FormKit will internationalize your tokens automatically — if your form is intended for a broadly international audience consider using date styles instead of tokens as this leads to a more readable date in many locales.
To include letters in the your format that are themselves tokens (like a
), you can escape those tokens with a backslash \
before the character:
The datepicker’s calendar popup has four "panels":
day
— Shows a traditional calendar view of a month with each day selectable.month
— Shows the 12 months of the year.year
— Shows a decade of years at a time.time
— Shows the time of day.When a user opens the datepicker’s popup, they will be shown one or more of these panels. You can modify which panels are displayed to the user and the sequence those panels should be displayed in by providing a sequence
prop. The default sequence
value is ['day']
(which allows you to navigate to the month
and year
panels).
For example, when selecting a birthday, it is natural to first select the birth year, then the month, then the day. The sequence
prop allows this behavior:
The time
panel can be used to allow a user to select a specific time of day. If you choose a format
that includes time (like YYYY-MM-DD HH:mm
), you’ll likely want to include time
panel to your sequence:
Like all inputs, the value
of the datepicker is both what is produced by the datepicker, and what is read back into the datepicker for hydration. By default, the format of the value is a UTC-normalized ISO8601 string (example: 2014-11-27T03:59:00.000Z
). However, this format can be changed to any of the supported date style or a token formats listed above by using the value-format
prop.
A valid question is why not always use ISO8601
? Although it’s the most popular way to work with dates — it’s machine and human readable — it’s not very human readable. For example, if your form sends a contact request email to a catering business, then ISO8601
would likely not be the best choice.
The value format must contain all the necessary data to re-constitute a date object, at a minimum this includes month, day, year. If your input requests information from the user that is not represented in your value format, those details will be lost.
To use a date style as the value, simply pass the style you’d like to use to the value-format
prop:
Values can also be represented in any arbitrary format by using formatting tokens:
Values passed to a datepicker must:
value-format
in the current value-locale
OR,Date
object.Although native Date
objects are always accepted as valid inputs for a datepicker, they will be immediately transformed into the value-format
specified.
value-format
Date
Since the format of the value needs to be parsed using the same locale it was created with, it is recommended to always specify the value-locale
when defining a custom value-format
. This ensures that no matter what the locale of the user entering the date is, the value will stay consistent:
Changing the value-locale
has no effect on the timezone
of the date being picked. See the timezone documentation below for further explanation.
Time is a notoriously hard thing to work with in any software environment, but especially browser-based JavaScript. The datepicker
provides some options to help work around these challenges.
In order to work with dates and times in JavaScript, it is useful to have a basic understanding of the Date
object. The date object in JavaScript is fundamentally a Unix timestamp (number of milliseconds since Jan 1 1970 at 00:00:00Z
). However, it is always localized to the client’s time. This localization is expressed in an an offset from UTC
. Your browser’s current time is:
When the offset is applied to the "clock time" you arrive at the current time in UTC:
When using value-format
tokens in the datepicker, those tokens will operate using the client’s timezone. For example, if your format requests the HH
token it would return:
Compare that to the above dates, and you’ll see it is the same as the hours
portion of the local time. Why does this matter? Read on.
Let’s consider a reservation app for a restaurant located in Amsterdam (UTC +100/+200
). It’s a popular destination for tourists and they often make reservations several weeks before they travel (while in their home country).
The datepicker, by default, will ask the tourist for the date and time of their desired reservation — but (by default) the selection will be their local time, not the time in Amsterdam. Even though the value-format
is outputting UTC, the time will not be the intended reservation time in Amsterdam (unless they happen to be in the same timezone).
Generally speaking, there are 2 solutions to this problem:
Use an "indeterminate" time (sometimes referred to as "wall time"). An indeterminate time is a time without a specific correlation the an underlying Unix Timestamp. For example, 2pm on March 13th
is not UTC and has no explicit offset. 2pm on March 13th
describes a specific time at an indeterminate location/timezone. You can do this with format tokens like (YYYY-MM-DD HH:mm
) as long as you do not use the offset in your value (Z
).
This would work for our restaurant app as long as a backend is able to attach an appropriate timezone or offset to this indeterminate time 2023-03-13 14:00 GMT+0100
to arrive at the appropriate UTC time (what this fictitious app requires in its database). The remaining challenge, for a backend developer, is knowing what offset to apply to the date to ensure it becomes "Amsterdam time" (this offset varies based on the time of year due to daylight savings in Europe/Amsterdam
).
timezone
propAlternatively, the timezone
prop of the datepicker will perform the offset correction for you automatically. Simply state "where" the datepicker is picking time for — in our example timezone="Europe/Amsterdam"
. The user’s experience will not change at all, but the time they select will be in the target timezone. A user in America/New_York
(+0400
) who selects 2pm on March 13th
in their datepicker, will yield a UTC value of 2023-03-13T13:00:00Z
which is 2pm
in Amsterdam. This allows for simple storage and hydration of your date using a UTC
format.
By default, the datepicker uses the client’s local timezone when a selection is made. The value of the output is determined by the value-format
(see above) — by default this is a UTC
normalized ISO8601
string. However, by specifying a custom format, you can achieve an "indeterminate" time (also called "wall time"). This is a date and/or time with no specific correlation to a given timezone.
For example, when you set an alarm on your phone for 8:00 AM
— that time is "indeterminate" — it has no correlation to timezone. If you live in Rome, and travel to Tokyo, your alarm will ring at 8:00 AM
in Tokyo the same as it would ring at 8:00 AM
in Rome. It’s impossible to represent a this as UTC.
You can achieve indeterminate time with the datepicker by providing no timezone or offset information in your value-format
— it is up to the interpreter of the date to add that information. The tokens in a value-format
always output local client values — so by leaving any timezone or offset (Z
) data out of the value, it is inherently "indeterminate":
For some applications, it is necessary to select the time in a given location — this can be quite challenging. To help ease this pain, the datepicker supports the ability to explicitly specify the timezone
of the input.
The timezone
prop lets you specify the "location" of the datepicker based on browser supported IANA timezones. This is important when you’d like to allow users to select a date and time in a given geographic location, no matter what the client’s location is. Some example use cases are:
There are plenty of times where the timezone
should not be used (default’s to client time):
In the example below, a user needs to pickup a rental car in Kolkata, India after an international flight. The user looks at their ticket — the flight arrives in Kolkata at 1:45 PM
. They’d like to pick the car up 45 minutes later at 2:30 PM
. These facts are true no matter where in the world the user is booking the trip from. In this case, we should set the timezone to Asia/Kolkata
. The offset in Kolkata is +5:30
— so selecting 2:30 PM
in Kolkata
is equivalent to 09:00 AM
UTC:
Most browsers ship with a comprehensive IANA database built into Intl.DateTimeFormat
. This is excellent since FormKit does not need to ship the (quite extensive) timezone database to the client’s browser. However, some older browser may not have the IANA database. This data can be polyfilled easily by using polyfill.io with Intl.DateTimeFormat.~timeZone.all
.
It is often necessary to disable specific dates in the datepicker. There are three ways to disable dates in the datepicker:
min-date
- a prop to control what the first available date is.max-date
- a prop to control what the last available date is.disabled-dates
- a prop to control whether or not any arbitrary date should be disabled.Any date that is disabled cannot be selected in the datepicker’s pop up, however an unavailable date can still be set as the initial value or by typing it into the input (when it isn’t in picker-only
mode). To handle these edge cases the datepicker has a built-in validation rule (that cannot be disabled) that ensures only valid dates can be submitted. The validation rule’s key is invalidDate
.
Often it is necessary to disable dates that are prior to a particular date. For example, booking a hotel room should only happen for dates in the future. To do this, use the min-date
prop with either an ISO8601
compatible string or a native Date
object:
To disable all dates after a given date, use the max-date
prop. For example, a birthday selector should only allow past dates. To do this, use the max-date
prop with either an ISO8601
compatible string or a native Date
object:
You can use min-date
and max-date
at the same time. Not only will this limit the range of dates, but additionally it will limit the available years to only valid years when using text entry.
Often our applications require substantially more granularity when disabling dates than min-date
and max-date
allows. The datepicker allows fine-grained control by leveraging the disabled-days
prop.
The disabled-days
prop expects a function that is passed 2 arguments: the core node and a Date
object. The responsibility of the function is to return a boolean indicating if the date is disabled (true
is disabled).
The disabled-days
prop supersedes min-date
and max-date
— you can choose to re-implement the base functionality by accessing node.props.minDate
or node.props.maxDate
.
It’s important that the provided function is fast and synchronous — it will be called frequently and repeatedly. For example, if you need to fetch information from a database, do it outside of this function and use this function to access memoized results.
When navigating the calendar pop up via keyboard, the datepicker will not allow you to select a disabled date. However this can be annoying as it can create areas of inaccessibility if some available dates are "sandwiched" between unavailable dates.
To make the user experience better, the datepicker will automatically scan forward or backward (depending on the direction desired) for the next available date to select. The maximum number of days to scan for an available day is controlled by the maxScan
prop (7 days by default):
Prop | Type | Default | Description |
---|---|---|---|
date-format | string | D | The token format to use in the calendar for dates in the month. |
disabled-days | function | min/max date logic | A function that is passed the core node and a `Date` object and must return if the date is disabled (`true` is disabled). |
format | string/object | date: 'long' | The format to display to the user in the select input. |
max-date | Date | ISO8601 | none | The maximum date the user is allowed to select. |
max-scan | number | 7 | The maximum number of days to scan forward or backward when looking for an available date to jump to via keyboard navigation. |
min-date | Date | ISO8601 | none | The earliest date the user is allowed to select. |
month-button-format | string | MMMM | The date format token to use for the month panel button in the calendar popup. |
month-format | string | MMMM | The date format token to use for each of the 12 months on the month panel. |
overlay | boolean | false | Whether or not to display a mask overlay. Read more about overlays in the mask input documentation (has no effect in pickerOnly` mode). |
picker-only | boolean | false | Whether or not to allow the date to be entered via text input. When picker-only is enabled, only the picker can be used to select a date. |
show-months | number | 1 | The number of months to render in the popup when on the day panel. |
sequence | array | ['day'] | The sequence of panels to walk a user through when they open the datepicker calendar view. Options are `year`, `month`, `day`, `time`. |
value-format | string/object | ISO8601 | The format to record as the value of the input. This can be composed with any token format, date style, or `ISO8601`. |
value-locale | string | `node.props.locale` | The locale to use for the `valueFormat`. When using format tokens in the `valueFormat` prop it is highly recommend to set an explicit `valueFormat`. |
week-start | number | 0 | The day of the week to start the `day` panel’s calendar on. 0-6 where 0 = Sunday and 6 = Saturday. |
week-day-format | string | d | The date format token used to render the day of the week column headers. |
year-format | string | YYYY | The date format token used to render the years in the `year` panel. |
Show Universal props | |||
config | Object | {} | Configuration options to provide to the input’s node and any descendent node of this input. |
delay | Number | 20 | Number of milliseconds to debounce an input’s value before the commit hook is dispatched. |
dirtyBehavior | string | touched | Determines how the "dirty" flag of this input is set. Can be set to touched or compare — touched (the default) is more performant, but will not detect when the form is once again matching its initial state. |
errors | Array | [] | Array of strings to show as error messages on this field. |
help | String | '' | Text for help text associated with the input. |
id | String | input_{n} | The unique id of the input. Providing an id also allows the input’s node to be globally accessed. |
ignore | Boolean | false | Prevents an input from being included in any parent (group, list, form etc). Useful when using inputs for UI instead of actual values. |
index | Number | undefined | Allows an input to be inserted at the given index if the parent is a list. If the input’s value is undefined, it inherits the value from that index position. If it has a value it inserts it into the lists’s values at the given index. |
label | String | '' | Text for the label element associated with the input. |
name | String | input_{n} | The name of the input as identified in the data object. This should be unique within a group of fields. |
parent | FormKitNode | contextual | By default the parent is a wrapping group, list or form — but this props allows explicit assignment of the parent node. |
prefix-icon | String | '' | Specifies an icon to put in the prefixIcon section. |
preserve | boolean | false | Preserves the value of the input on a parent group, list, or form when the input unmounts. |
preserve-errors | boolean | false | By default errors set on inputs using setErrors are automatically cleared on input, setting this prop to true maintains the error until it is explicitly cleared. |
sections-schema | Object | {} | An object of section keys and schema partial values, where each schema partial is applied to the respective section. |
suffix-icon | String | '' | Specifies an icon to put in the suffixIcon section. |
type | String | text | The type of input to render from the library. |
validation | String, Array | [] | The validation rules to be applied to the input. |
validation-visibility | String | blur | Determines when to show an input's failing validation rules. Valid values are blur , dirty , and live . |
validation-label | String | {label prop} | Determines what label to use in validation error messages, by default it uses the label prop if available, otherwise it uses the name prop. |
validation-rules | Object | {} | Additional custom validation rules to make available to the validation prop. |
value | Any | undefined | Seeds the initial value of an input and/or its children. Not reactive. Can seed entire groups (forms) and lists.. |
You can target a specific section of an input using that section's "key", allowing you to modify that section's classes, HTML (via :sections-schema
), or content (via slots). Read more about sections here.
This section is located inside the inner
section when the overlay
prop is added.
The panel appears below the input element inside the inner
section when the datepicker popup is open.
The panel appears below the input element inside the inner
section when the datepicker popup is open.
The panel appears below the input element inside the inner
section when the datepicker popup is open.
The panel appears below the input element inside the inner
section when the datepicker popup is open.
Section-key | Description |
---|---|
calendar | The wrapper immediately around the calendar on the day panel. |
calendarHeader | The wrapper around the header columns on the day panel. |
calendarWeeks | The wrapper immediately around each row of weeks on the day panel. |
day | The content of the day — by default contains the numeric day. In this slot/section you can use context.day ($day in schema) to get the date object for the given day. |
dayButton | The button displayed in the header of the time panel which navigates to the day panel. |
dayCell | The wrapper immediately around the date section. In this slot/section you can use context.day ($day in schema) to get the date object for the given day. |
daysHeader | The wrapper around the header columns on the date panel. |
month | The section that renders the actual month names on the month panel. In this slot/section you can use context.month ($month in schema) to get the date object for the given month. |
monthButton | The button in the header of the day and time panels that navigates to the month panel. |
months | The wrapper immediately around the month sections on the month panel. |
monthsHeader | The wrapper immediately around the header buttons (yearButton) on the month panel. |
next | In the panel header the button responsible for navigating to the next month or decade. |
nextLabel | The section responsible for rendering the text content of the next button in the panel header. |
openButton | The button responsible for opening the picker dialog. |
overlay | The outer wrapper of the overlay. The overlay is used to mimc the text that is in the text input during text-entry mode to allow for styling. |
overlayChar | A section containing overlay characters of type char |
overlayEnum | A section containing overlay characters of type enum |
overlayInner | An inner wrapper immediately inside the overlay section. |
overlayLiteral | A section containing overlay characters of type literal |
overlayParts | A section containing all the overlay parts as immediate children. |
overlayPlaceholder | A section containing overlay characters of type placeholder. |
panel | A wrapper around the currently active panel. This is rendered below the panelHeader as a sibling. |
panelHeader | A wrapper around the header of each panel where the panel’s navigation buttons are located. This is a sibling of the panel section. |
panelWrapper | A wrapper around the panel and panelHeader sections, this section is responsible for showing or hiding the picker dialog. |
prev | In the panel header the button responsible for navigating to the previous month or decade. |
prevLabel | The section responsible for rendering the text content of the prev button in the panel header. |
time | The time panel that contains the timeInput. |
timeHeader | The panel header of the time panel with navigation buttons to the year, month, and day panels. |
timeInput | A native HTML time input responsible for setting the time of the selected date. |
week | A wrapper around a row of 7 days on the day panel. |
weekDay | The cell responsible for rendering the day of the week in the calendar header of the day panel (M, T, W etc...). |
weekDays | The wrapper element around the days of the week on the calendar’s header on the day panel. |
year | The element responsible for rendering each of the years available on the year panel. |
yearButton | The button in the header of the month, day, and time panels that navigates to the year panel. |
years | The years panel, responsible for rendering a decade of years at a time. |
yearsHeader | The panel header when on the years panel, shows the current decade year range. |
Show Universal section keys | |
outer | The outermost wrapping element. |
wrapper | A wrapper around the label and input. |
label | The label of the input. |
prefix | Has no output by default, but allows content directly before an input element. |
prefixIcon | An element for outputting an icon before the prefix section. |
inner | A wrapper around the actual input element. |
suffix | Has no output by default, but allows content directly after an input element. |
suffixIcon | An element for outputting an icon after the suffix section. |
input | The input element itself. |
help | The element containing help text. |
messages | A wrapper around all the messages. |
message | The element (or many elements) containing a message — most often validation and error messages. |