Pro installation quickstart 🚀

Basic example

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.

Datepicker Overview

5 mins

Load live example

Modes

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.

Dual entry

  • Text entry - By default, users can click or tab into any of the "parts" of the displayed date (month, date, year, etc.) in the text input and type their desired value. Matching values will be displayed with automatic completion. In addition to typing, users can hit the up/down arrow keys to cycle through available options for each segment.
  • Picker entry - By clicking the "calendar" icon to the right of the input, users can also display a calendar popup to select their date visually:
Load live example
Placeholder & Overlay

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.

Picker only

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:

Load live example

Date format

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.

Styled formats

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' }).

Load live example

Date styles

Enable any of the following date styles with the format prop:

Format StyleExamples
fullWednesday, March 1, 2023, Mercoledì 1 marzo 2023
longMarch 1, 2023, 1 marzo 2023
mediumMar 6, 2023, 6 mar 2023
short3/1/23, 1/3/23

Time styles

Format styleExamples
long7:05:00 PM, 19:05:00
medium7:05:00 PM, 19:05:00
short7:05 PM, 19:05

Token formats

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.

Dates required

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.

TokenExamplesDescription
YY99, 23, 002 digit year
YYYY1999, 2023, 21004 digit year
M1, 12The month 1-12
MM01, 12The month 01-12
MMMJan, FebShort name Jan-Dec
MMMMJanuary, FebruaryFull name January - December
D1, 9, 22The day of the month 1-31
DD01, 09, 22The day of the month 01-31
dM, T, W, T, F, S, SSingle digit day "T"
dddThu, SatShort day name "Thu"
ddddMonday, TuesdayFull day name "Wednesday"
H0, 13, 23Minimum hour digits, 24 hour, 0-23
HH00, 13, 232 hour digits, 24 hour, 00-23
h12, 1, 11Minimum hour digits, 12 hour clock, 1-12
hh12, 01, 112 hour digits, 12 hour clock, 01-12
m1, 59The minute 0-59
mm01, 59The minute 00-59
s1, 59The second 0-59
ss01, 59The second 00-59
aam, pmam/pm
AAM, PMAM/PM
Internationalization

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.

Load live example

Escaping tokens

To include letters in the your format that are themselves tokens (like a), you can escape those tokens with a backslash \ before the character:

Load live example

Panel sequence

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:

Load live example

Selecting time

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:

Load live example

Values

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.

Complete dates

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.

Date styles

To use a date style as the value, simply pass the style you’d like to use to the value-format prop:

Load live example

Token formats

Values can also be represented in any arbitrary format by using formatting tokens:

Load live example

Setting values (hydrating)

Values passed to a datepicker must:

  1. Match the value-format in the current value-locale OR,
  2. Be a native JavaScript 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.

Matching the value-format

Load live example

Using a native Date

Load live example

Value locale

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:

Timezone vs Locale

Changing the value-locale has no effect on the timezone of the date being picked. See the timezone documentation below for further explanation.

Load live example

Timezones

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.

Timezones, dates, and formats case study

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:

Client (browser) time

When the offset is applied to the "clock time" you arrive at the current time in UTC:

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:

HH format token

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.

A case study

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:

Option 1: Indeterminate time

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).

Options 2: Using the datepicker’s timezone prop

Alternatively, 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.

Indeterminate timezone

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":

Load live example

Specifying a timezone

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:

  • Restaurant reservations
  • Car rental pickup time
  • Hotel check in time

There are plenty of times where the timezone should not be used (default’s to client time):

  • Scheduling a Zoom meeting
  • Setting a reminder notification
  • Creating a calendar event

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:

Load live example
Polyfilling Timezones

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.

Disabling dates

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.

Min date

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:

Load live example

Max date

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:

Load live example
Min & max dates together

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.

Disabled days

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.

Fast and synchronous

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.

Example: disabled weekends

Load live example

Example: fetch from API

Load live example

Scan for availability

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):

Example: max-scan

Load live example

Clearable

The datepicker input can be cleared by clicking the "clear" button that appears when the input has a value — this clear button only appears when the clearable prop is added:

Load live example

Props & Attributes

PropTypeDefaultDescription
clearablestringfalseAdds a clear button to the right of the value. This button only appears when the input has a completed value.
date-formatstringDThe token format to use in the calendar for dates in the month.
disabled-daysfunctionmin/max date logicA function that is passed the core node and a `Date` object and must return if the date is disabled (`true` is disabled).
formatstring/objectdate: 'long'The format to display to the user in the select input.
max-dateDate | ISO8601noneThe maximum date the user is allowed to select.
max-scannumber7The maximum number of days to scan forward or backward when looking for an available date to jump to via keyboard navigation.
min-dateDate | ISO8601noneThe earliest date the user is allowed to select.
month-button-formatstringMMMMThe date format token to use for the month panel button in the calendar popup.
month-formatstringMMMMThe date format token to use for each of the 12 months on the month panel.
overlaybooleanfalseWhether or not to display a mask overlay. Read more about overlays in the mask input documentation (has no effect in pickerOnly` mode).
picker-onlybooleanfalseWhether 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-monthsnumber1The number of months to render in the popup when on the day panel.
sequencearray['day']The sequence of panels to walk a user through when they open the datepicker calendar view. Options are `year`, `month`, `day`, `time`.
value-formatstring/objectISO8601The format to record as the value of the input. This can be composed with any token format, date style, or `ISO8601`.
value-localestring`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-startnumber0The day of the week to start the `day` panel’s calendar on. 0-6 where 0 = Sunday and 6 = Saturday.
weekday-formatstringdThe date format token used to render the day of the week column headers.
year-formatstringYYYYThe date format token used to render the years in the `year` panel.
popoverbooleanfalseRenders the input's UI panel using the browser Popover API.
Show Universal props
configObject{}Configuration options to provide to the input’s node and any descendent node of this input.
delayNumber20Number of milliseconds to debounce an input’s value before the commit hook is dispatched.
dirtyBehaviorstringtouchedDetermines how the "dirty" flag of this input is set. Can be set to touched or comparetouched (the default) is more performant, but will not detect when the form is once again matching its initial state.
errorsArray[]Array of strings to show as error messages on this field.
helpString''Text for help text associated with the input.
idStringinput_{n}The unique id of the input. Providing an id also allows the input’s node to be globally accessed.
ignoreBooleanfalsePrevents an input from being included in any parent (group, list, form etc). Useful when using inputs for UI instead of actual values.
indexNumberundefinedAllows 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.
labelString''Text for the label element associated with the input.
nameStringinput_{n}The name of the input as identified in the data object. This should be unique within a group of fields.
parentFormKitNodecontextualBy default the parent is a wrapping group, list or form — but this props allows explicit assignment of the parent node.
prefix-iconString''Specifies an icon to put in the prefixIcon section.
preservebooleanfalsePreserves the value of the input on a parent group, list, or form when the input unmounts.
preserve-errorsbooleanfalseBy 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-schemaObject{}An object of section keys and schema partial values, where each schema partial is applied to the respective section.
suffix-iconString''Specifies an icon to put in the suffixIcon section.
typeStringtextThe type of input to render from the library.
validationString, Array[]The validation rules to be applied to the input.
validation-visibilityStringblurDetermines when to show an input's failing validation rules. Valid values are blur, dirty, and live.
validation-labelString{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-rulesObject{}Additional custom validation rules to make available to the validation prop.
valueAnyundefinedSeeds the initial value of an input and/or its children. Not reactive. Can seed entire groups (forms) and lists..

Sections

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.

View on a larger screen to see this section diagram.

Select a date
November 26, 2014
📅
Pick your arrival date.
Sorry, that date is not available.

Overlay

This section is located inside the inner section when the overlay prop is added.

View on a larger screen to see this section diagram.

Years panel

The panel appears below the input element inside the inner section when the datepicker popup is open.

View on a larger screen to see this section diagram.

2010 - 2020
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019

Months panel

The panel appears below the input element inside the inner section when the datepicker popup is open.

View on a larger screen to see this section diagram.

2027
X
Jan
Feb
Mar
Apr
May
Jun
Jul
Aug
Sep
Oct
Nov
Dec

Day panel

The panel appears below the input element inside the inner section when the datepicker popup is open.

View on a larger screen to see this section diagram.

Feb
2026
X
S
M
T
W
T
F
S
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

Time panel

The panel appears below the input element inside the inner section when the datepicker popup is open.

View on a larger screen to see this section diagram.

February
17
2027
X
12:00 AM

Section keys

Section-keyDescription
calendarThe wrapper immediately around the calendar on the day panel.
calendarHeaderThe wrapper around the header columns on the day panel.
calendarWeeksThe wrapper immediately around each row of weeks on the day panel.
dayThe 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.
dayButtonThe button displayed in the header of the time panel which navigates to the day panel.
dayCellThe 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.
daysHeaderThe wrapper around the header columns on the date panel.
monthThe 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.
monthButtonThe button in the header of the day and time panels that navigates to the month panel.
monthsThe wrapper immediately around the month sections on the month panel.
monthsHeaderThe wrapper immediately around the header buttons (yearButton) on the month panel.
nextIn the panel header the button responsible for navigating to the next month or decade.
nextLabelThe section responsible for rendering the text content of the next button in the panel header.
panelCloseThe section responsible for rendering the close button of the datepicker, shown on small touch devices.
closeIconThe icon rendered inside the panelClose section.
openButtonThe button responsible for opening the picker dialog.
overlayThe 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.
overlayCharA section containing overlay characters of type char
overlayEnumA section containing overlay characters of type enum
overlayInnerAn inner wrapper immediately inside the overlay section.
overlayLiteralA section containing overlay characters of type literal
overlayPartsA section containing all the overlay parts as immediate children.
overlayPlaceholderA section containing overlay characters of type placeholder.
panelA wrapper around the currently active panel. This is rendered below the panelHeader as a sibling.
panelHeaderA wrapper around the header of each panel where the panel’s navigation buttons are located. This is a sibling of the panel section.
panelWrapperA wrapper around the panel and panelHeader sections, this section is responsible for showing or hiding the picker dialog.
prevIn the panel header the button responsible for navigating to the previous month or decade.
prevLabelThe section responsible for rendering the text content of the prev button in the panel header.
timeThe time panel that contains the timeInput.
timeHeaderThe panel header of the time panel with navigation buttons to the year, month, and day panels.
timeInputA native HTML time input responsible for setting the time of the selected date.
weekA wrapper around a row of 7 days on the day panel.
weekDayThe cell responsible for rendering the day of the week in the calendar header of the day panel (M, T, W etc...).
weekDaysThe wrapper element around the days of the week on the calendar’s header on the day panel.
yearThe element responsible for rendering each of the years available on the year panel.
yearButtonThe button in the header of the month, day, and time panels that navigates to the year panel.
yearsThe years panel, responsible for rendering a decade of years at a time.
yearsHeaderThe panel header when on the years panel, shows the current decade year range.
Show Universal section keys
outerThe outermost wrapping element.
wrapperA wrapper around the label and input.
labelThe label of the input.
prefixHas no output by default, but allows content directly before an input element.
prefixIconAn element for outputting an icon before the prefix section.
innerA wrapper around the actual input element.
suffixHas no output by default, but allows content directly after an input element.
suffixIconAn element for outputting an icon after the suffix section.
inputThe input element itself.
helpThe element containing help text.
messagesA wrapper around all the messages.
messageThe element (or many elements) containing a message — most often validation and error messages.

Accessibility

All FormKit inputs are designed with the following accessibility considerations in mind. Help us continually improve accessibility for all by filing accessibility issues here:

Semantic markupAria attributesKeyboard accessibleFocus indicatorsColor contrast with the provided themeAccessible labels, help text, and errors
Section KeyAttributeDefaultDescription
panelWrappertabindex-1 or 0Prioritizes keyboard focus order by setting it to -1 when disabled and 0 when enabled.
aria-modaltrueIndicates the modal dialog is present and it blocks interaction with other elements on the page.
aria-labelProvides an accessible name.
weekDayaria-labelProvides an accessible name.
dayCelltabindex-1 or 0Prioritizes keyboard focus order by setting it to 0 when its the same day and -1 when its not.
aria-selectedIndicates whether the day is currently selected.
aria-labelProvides an accessible name.
openButtontabindex-1 or 0Prioritizes keyboard focus order by setting it to -1 when its in picker only mode and 0 when its not.
aria-labelProvides an accessible name.
aria-haspopuptrueSignals the presence of a pop-up menu or dialog triggered by this interaction.
aria-expandedIndicates whether the colorpicker element is currently expanded or collapsed.
aria-controlsLinks this element to the ID of the listbox element.
yeartabindex-1 or 0Prioritizes keyboard focus order by setting it to 0 when its the same year and -1 when its not.
aria-selectedIndicates whether the year is currently selected.
monthtabindex-1 or 0Prioritizes keyboard focus order by setting it to 0 when its the same month and -1 when its not.
aria-selectedIndicates whether the month is currently selected.
panelHeaderaria-livepoliteAnnouces to screen readers that this element was dynamically updated without interrupting the current task.
dayButtontabindex2Prioritizes keyboard focus order by setting it to 2.
removeSelectionaria-controlsLinks this element to the ID of the input element.
panelClosetabindex-1Prioritizes keyboard focus order by setting it to -1.
aria-labelProvides an accessible name.
Show Universal section key
labellabelforAssociates the label to an input element. Users can click on the label to focus the input or to toggle between states.
inputinputdisabledDisables an HTML element, preventing user interaction and signaling a non-interactive state.
aria-describedbyAssociates an element with a description, aiding screen readers.
aria-requiredAdds this attribute when validation is required.
iconiconforWhenever icon is defined as a label it links it to an input element.

Keyboard Interactions

Keyboard EventDescription
TabMoves the focus to the next focusable input on the page.
Shift + TabMoves the focus to the previous focusable input on the page.