Date input
A text field that can be typed into, with a VDatePicker in a panel beside it. The mask follows the language: the field order, the separator and the placeholder are all derived from the locale.
Usage
Examples
Label, hint and icon
label and hint behave as on any field. pickerIcon changes the glyph that opens the calendar, iconStart puts an icon at the start of the field, and loading shows a spinner in place of the calendar icon. pickerIconLabel, clearLabel, loadingText and iconStartLabel rename what each of them announces.
Type it or pick it from the calendar
The calendar is the only way in
An icon at the start, a spinner at the end while something loads
Sizes
size sets the field height to 32, 40 or 48 pixels, and compact takes 4px off it. The panel keeps its own measurements.
Modes
mode chooses how the value is filled in: input masks the field so only digits are typed, the calendar then being opt-in through showPicker; picker makes the calendar the only way in. Typing is reserved for a single date.
No icon, no panel: the field is the whole control
showPicker adds the icon and opens the panel on focus
Nothing can be typed, so the calendar is the only way in
Range
selection set to range makes the value a start and an end, the calendar taking the first click as one and the second as the other.
Pick the first day, then the last. Typing falls back to read-only here.
Multiple dates
selection set to multiple makes the value a list, a day already in it being taken back out by clicking it again.
Click a day to add it, click it again to take it back
Presets
The #footer slot is a strip at the foot of the panel, for actions or for the dates a reader reaches for most. It receives close, so a button can set the value and dismiss the panel at once.
Bounds and closed dates
min and max bound both the choice and the navigation. disabledDates closes individual days, as a list or as a function answering for one date at a time.
Between 5 and 24 June 2026: the arrows stop at the bounds
Weekends are struck through: still reachable, never choosable
Event dots
events draws up to three dots under a day. Each takes any CSS colour and a label, which is what assistive technology reads.
Open the calendar: June has four marked days
Custom day cells
The #day slot replaces the number inside a day and receives the ISO date along with what the cell knows about itself: whether it belongs to the month on screen, whether it can be chosen, whether it is selected, today, or inside a period being drawn.
The slot replaces the day number, so what it draws follows the selection
Clearable
clearable adds a cross that empties the value, to the left of the calendar icon rather than in its place.
The cross sits to the left of the calendar icon, never in its place
Emptying the field is then the reader's own business
Adjacent days
showAdjacentDays fills the corners of the grid with the neighbouring months, greyed and inert. selectAdjacentDays makes those days choosable as well, and picking one moves the calendar to its month.
The grid starts and ends on the month itself
The corners are filled with the neighbouring months, greyed and inert
Choosing one moves the calendar to its month
States
invalid marks the field as having an error. disabled greys it out and prevents the panel from opening. readonly shows the value frozen: nothing can be typed and no calendar is rendered, but the field keeps its contrast and takes the focus.
For a rule the browser cannot check by itself
Greyed through the colour tokens, and the panel can no longer be opened
No typing, no calendar, no clear cross
Localization
locale decides the typing order, the separator, the month and day names and the first day of the week, and takes precedence over the global locale. displayFormat is a set of Intl options for writing the date out, and applies wherever nothing is typed.
displayFormat is an Intl option bag, and it only applies where nothing is typed
Placement
placement names the preferred opening direction of the panel, above or below the field.
API
Props
| Prop | Type | Default |
|---|---|---|
selection | DatePickerSelection'single' | 'range' | 'multiple' | 'single' |
| What is being chosen: one date, a period between two, or several separate dates. | ||
locale | string | none |
| A BCP 47 locale, which decides the month and day names, the first day of the week and the order the field is typed in. It takes precedence over the design system's global locale and falls back to it. | ||
firstDayOfWeek | number | none |
| Forces the day the weeks start on, from 0 for Sunday to 6 for Saturday. | ||
min | string | none |
| The earliest date that can be chosen, as an ISO string. | ||
max | string | none |
| The latest date that can be chosen, as an ISO string. | ||
disabledDates | DatePickerMatcher | none |
| Dates that cannot be chosen, as a list or as a function. | ||
showAdjacentDays | boolean | false |
| Fills the corners of the grid with the greyed days of the neighbouring months. | ||
selectAdjacentDays | boolean | false |
| Lets those neighbouring days be clicked, which implies showing them. | ||
events | DatePickerEvent[] | none |
| Events to mark under the days they fall on. | ||
mode | DateInputMode'picker' | 'input' | 'input' |
Whether the field can be typed into, using the numeric form of the reader's language, or is filled from the calendar alone, which is picker. Typing is reserved for choosing a single date: a period or a list falls back to picker, there being no sensible way to type either. It is a different question from readonly, which freezes the field by every route at once. | ||
showPicker | boolean | false |
Offers the date picker alongside a field that can be typed into: an icon at the end of the field, and a panel that opens on focus. It means nothing in picker mode, where the calendar is already the only way to choose. | ||
label | string | none |
| The label above the field. | ||
hint | string | none |
| A line of help under the field. | ||
placeholder | string | none |
| What the field says while empty. | ||
size | DateInputSize'sm' | 'md' | 'lg' | 'md' |
| The height of the field: 32, 40 or 48 pixels. | ||
compact | boolean | false |
| Takes 4px off the height. | ||
disabled | boolean | false |
| Makes the field unusable, greyed out through the colour tokens. | ||
readonly | boolean | false |
Shows the date without letting it be changed: nothing can be typed, there is no calendar and no clear cross, and the attributes announcing a panel go with it. The field keeps the focus and can be copied from, which is what separates it from disabled. | ||
invalid | boolean | false |
| Marks the field as invalid, for a rule of your own. | ||
iconStart | IconSource | none |
An icon inside the field, at the start. Decorative until a @click:icon-start listener turns it into a button. | ||
iconStartLabel | string | none |
| What the start icon does, in words, once it is clickable. | ||
pickerIconLabel | string | none |
| What the end icon does, in words. It names the button that opens the calendar, and falls back to the design system dictionary. | ||
loading | boolean | false |
| Shows a spinner in place of the calendar icon. It says that something is being loaded and changes nothing else: the field can still be typed into and the panel still opens. | ||
loadingText | string | none |
| What screen readers announce while the spinner turns. It falls back to the design system dictionary. | ||
clearable | boolean | false |
| Offers a cross that empties the value, shown before the end icon. | ||
clearLabel | string | none |
| What that cross does, in words. It falls back to the design system dictionary. | ||
pickerIcon | IconSource | calendar_today |
| The icon that opens the date picker, at the end of the field. The clear cross appears to its left rather than in its place, and no icon is rendered at all when there is no panel to open. | ||
displayFormat | Intl.DateTimeFormatOptions | { day: 'numeric', month: 'short', year: 'numeric' } |
How the date is written out in the field. It has no effect on a field being typed into, which necessarily shows the numeric form one types, so it concerns picker mode and the period and list selections. | ||
placement | DateInputPlacement'bottom' | 'bottom-start' | 'bottom-end' | 'top' | 'top-start' | 'top-end' | 'bottom-start' |
| Where the panel opens relative to the field. | ||
v-model | DatePickerValue | null |
The date or dates chosen, in the shape selection calls for. While the reader types, it is only written once what they have entered is a complete and acceptable date; an unfinished or refused entry leaves it untouched and is reverted when they leave the field. | ||
Events
| Event | Type |
|---|---|
click:icon-start | [event: MouseEvent] |
The start icon was clicked. Attaching this listener is what turns that icon into a real button, which then needs iconStartLabel. | |
clear | [] |
| The clear cross emptied the field. The value has already been reset. | |
Slots
| Slot | Type |
|---|---|
start | {} |
Content at the start of the field, rendered after iconStart rather than in its place. | |
value-end | {} |
Controls of your own inside the field, placed before the ones the field owns: the clear cross and the icon that opens the panel. Those two are the component own affordance, which is why there is no end slot here. | |
day | DatePickerDaySlotProps |
| What a day cell shows, handed straight to the calendar. | |
footer | DateInputFooterSlotProps |
The strip at the foot of the panel: actions, or preset dates such as today. It receives close, which is what lets one of those buttons dismiss the panel. | |
Types
The types the tables above name, written as the library declares them. The ones carrying export can be imported from vectis-ui to type your own code; the others are the shape of what a slot hands out.
export interface BuiltinIcon {
name: string
paths: readonly [string] | readonly [string, string]
}export interface DatePickerDaySlotProps {
iso: string
day: number
inMonth: boolean
disabled: boolean
selected: boolean
today: boolean
inRange: boolean
events: DatePickerEvent[]
}export interface DatePickerEvent {
date: string
color?: string
label?: string
}export type DatePickerMatcher = string[] | ((iso: string) => boolean)
export interface DatePickerRange {
start: string | null
end: string | null
}export type DatePickerValue = string | null | DatePickerRange | string[]
export type IconRender =
| { path: string; viewBox?: string }
| { component: Component; props?: Record<string, unknown> }
| { src: string }
| { text: string; class?: string }
| { class: string }export type IconSource = string | BuiltinIcon | IconRender