DatePicker
Three components over one implementation: WxDatePicker (a date), WxDateTimePicker (a date and a time) and WxTimePicker (a time). They wrap @vuepic/vue-datepicker — calendars are a lot of behaviour to get right, and that library already has.
Model: 2026-03-14
Model: 2026-03-14 09:30
Model: 09:00
The deadline field is required.
The model is a string, in the backend's format
By default the model holds exactly what a Laravel column expects, so the value can go to the API and come back without a conversion step anywhere:
| Component | Model | Field shows |
|---|---|---|
WxDatePicker | 2026-03-14 | 14.03.2026 |
WxDateTimePicker | 2026-03-14 09:30 | 14.03.2026 09:30 |
WxTimePicker | 09:30 | 09:30 |
Add seconds and both the stored and the shown value gain :ss. An empty field is null, never an empty string.
<script setup lang="ts">
import { ref } from 'vue'
const publishedAt = ref('2026-03-14')
</script>
<template>
<wx-date-picker v-model="publishedAt" placeholder="Pick a date" />
</template>Override either side when the backend disagrees, or opt out of strings entirely:
<template>
<!-- stored as 14/03/2026, shown as 2026.03.14 -->
<wx-date-picker v-model="value" value-format="dd/MM/yyyy" format="yyyy.MM.dd" />
<!-- the model holds a Date object -->
<wx-date-picker v-model="date" value-format="date" />
</template>Props
All three take the same props; WxDateTimePicker and WxTimePicker simply fix type.
| Prop | Type | Default | Description |
|---|---|---|---|
modelValue | string | Date | null | null | Current value |
type | 'date' | 'datetime' | 'time' | 'date' | What is being picked |
valueFormat | string | per type | Format the value is stored in; 'date' keeps a Date |
format | string | per type | Format the field shows |
placeholder | string | — | Placeholder text |
clearable | boolean | true | Show the clear button |
minDate | string | Date | — | Earliest selectable date |
maxDate | string | Date | — | Latest selectable date |
seconds | boolean | false | Include seconds |
minutesIncrement | number | 1 | Step of the minutes column |
is24 | boolean | true | 24-hour clock |
locale | string | Locale | the browser | Language of the calendar |
timezone | string | the reader's | IANA zone a moment is shown and picked in |
weekStart | number | 1 | 0 is Sunday, 1 is Monday |
autoApply | boolean | true | Apply on pick, with no confirm button |
textInput | boolean | false | Allow typing as well as picking |
teleport | boolean | string | true | Render the menu in a portal |
size | 'sm' | 'md' | 'lg' | 'md' | Control height |
status | 'default' | 'success' | 'warning' | 'error' | 'default' | Validation state |
disabled | boolean | false | Disables the field |
readonly | boolean | false | Read-only field |
id | string | generated | Overrides the id the label points at; WxFormItem supplies one |
name | string | — | name of the underlying input |
ariaLabel | string | — | Label when there is no visible one |
Events: update:modelValue, change, clear, open, close.
teleport is on by default on purpose: a picker inside a WxCard or a scrolling table would otherwise be clipped by overflow: hidden.
Language
The library underneath carries exactly one language, en-US, so a calendar left alone heads a Russian screen with "Sep 2026" over a "Mo Tu We" row. locale takes a BCP-47 tag and the month and weekday names come from the browser's own Intl data — no language packs to import, and any tag the browser knows works:
<template>
<wx-date-picker v-model="publishedAt" locale="ru" />
</template>An application in one language throughout says it once, and every picker under it follows — that is what an admin panel wants, because the calendar has to follow the language the user picked in the interface rather than the one their browser is set to:
import { dateLocaleKey } from '@webx-ui/core'
app.provide(
dateLocaleKey,
computed(() => i18n.state.locale),
)provideDateLocale(locale) does the same from inside a component. A locale prop on a field still wins over both, and with neither the browser's own language is used.
The library's own convention — a date-fns locale object — is still accepted, for a language the browser does not carry or a calendar that needs wording of its own. date-fns comes along with the picker, so it is importable without installing anything else:
<script setup lang="ts">
import { uk } from 'date-fns/locale'
</script>
<template>
<wx-date-picker v-model="value" :locale="uk" />
</template>Timezone
A value with an offset — valueFormat: "yyyy-MM-dd'T'HH:mm:ssXXX" — is a moment, and on its own the picker draws it on the reader's clock: an event at 09:30 in Hong Kong reads 04:30 to an editor in Moscow, and what they pick goes back with Moscow's offset. timezone names the zone the field reads and writes instead, whatever the machine is set to:
<wx-date-time-picker
v-model="startsAt"
value-format="yyyy-MM-dd'T'HH:mm:ssXXX"
timezone="Asia/Hong_Kong"
/>
<!-- shows "12.10.2026 09:30 GMT+08:00" anywhere; sends "2026-10-12T09:30:00+08:00" -->When that zone is not the reader's own, the default display format names its offset after the time. A site has one clock, so a panel says it once — app.provide(dateTimezoneKey, …) or provideDateTimezone() — and the WebX panel does so with the site's own zone. A value without an offset is a wall clock already (a Laravel datetime column read as written) and is never moved.
Anything else the library takes
Unknown attributes are passed straight through to the underlying picker, so its whole prop surface stays reachable without us re-declaring it:
<template>
<wx-date-picker v-model="value" :disabled-week-days="[6, 0]" range />
</template>Theming
The library's --dp-* variables are mapped onto WebX tokens, so the calendar follows the theme, dark mode included, without its dark prop. Restyling the picker means overriding the same tokens as everything else — see Theming.
Accessibility
- Inside a
WxFormItem, the generated id reaches the real<input>, so the label'sforworks and the error message is linked byaria-describedby. - The error state is passed to the library the way it expects, so the field is marked invalid rather than merely coloured.
- Keyboard navigation inside the calendar comes from the library: arrows move, Enter picks, Escape closes.
Bundle size
@vuepic/vue-datepicker is a real dependency of @webx-ui/core, installed automatically. It is not bundled into our output — your app resolves and de-duplicates it — but its stylesheet is part of @webx-ui/core/style.css, about 4 kB gzipped, whether or not you use a picker.