@contactless/vue-datepicker
| Install | |
|---|---|
npm install @contactless/vue-datepicker |
|
| Latest Version: | 0.4.12 |
| Vue: | 3 |
| License: | Custom |
| Last Updated: | Aug 25, 2026 |
| Links: | Bitbucket · npm |
@contactless/vue-datepicker
Public Vue 3 datepicker with Vaadin-style linked month/year scroll, published under the @contactless npm scope.
Install
npm i @contactless/vue-datepicker
Usage
<script setup lang="ts">
import { ref } from 'vue'
import { ContactlessDatePicker } from '@contactless/vue-datepicker'
import '@contactless/vue-datepicker/style.css'
const value = ref<string | null>(null)
</script>
<template>
<ContactlessDatePicker
v-model="value"
:enable-time="false"
:i18n="{
today: 'Today',
reset: 'Reset',
}"
/>
</template>
Custom input
By default the picker renders a built-in text field. Provide your own trigger via the #input slot:
<ContactlessDatePicker v-model="value">
<template #input="{ value, placeholder, disabled, open, readonly, inputMode, onFocus, onPointerDown, onInput, onBlur, onKeydown }">
<input
type="text"
:value="value"
:placeholder="placeholder"
:disabled="disabled"
:readonly="readonly"
:inputmode="inputMode"
:class="{ 'is-open': open }"
@pointerdown="onPointerDown"
@focus="onFocus"
@input="onInput(($event.target as HTMLInputElement).value)"
@blur="onBlur"
@keydown="onKeydown"
/>
</template>
</ContactlessDatePicker>
Wire the slot handlers so typing, blur parsing, keyboard shortcuts, and opening the overlay keep working. The DatePickerInputSlotProps type is exported for TypeScript consumers.
| Slot prop | Description |
|---|---|
value |
Formatted display text synced from modelValue |
placeholder |
From the placeholder prop |
disabled |
From the disabled prop |
open |
Whether the calendar overlay is open |
readonly |
true on mobile so the field is calendar-only (no soft keyboard) |
inputMode |
'none' on mobile, 'text' on desktop |
onFocus |
Opens the picker |
onPointerDown |
Unlocks typing on desktop (fine pointer) only |
onInput |
Updates typed text ((value: string) => void) |
onBlur |
Parses input and commits to modelValue |
onKeydown |
Handles Enter (commit + close, keep focus) and Escape (close) |
Props
| Prop | Type | Default | Notes |
|---|---|---|---|
modelValue |
string | Date | [string|Date, string|Date] | null |
null |
v-model |
mode |
'single' | 'range' |
'single' |
|
enableTime |
boolean |
false |
Model becomes yyyy-MM-dd'T'HH:mm when formats unset |
min / max |
Date | string |
— | Inclusive day bounds |
isDateDisabled |
(date: Date) => boolean |
— | Extra disable rules |
formats |
{ input, model } |
date-fns patterns | Override display / emit formats |
autoApply |
boolean |
true |
Close on day select when time is off |
disabled |
boolean |
false |
|
placeholder |
string |
'' |
|
dir |
'ltr' | 'rtl' |
'ltr' |
Year strip mirrors in RTL |
i18n |
{ months, weekdays, today, reset, hours, minutes, date, time } |
English defaults | Pass translated labels from the app |
Overlay placement
The calendar teleports to document.body and opens below the field when it fits. If the field is near the bottom of the viewport (or a scroll/keyboard shrink leaves more room above), it flips above. Placement is recomputed on resize and visualViewport changes.
On touch / coarse pointers (and viewports narrower than the desktop date+time overlay), the picker uses a compact layout that matches the field width:
- Date+time: Date / Time tabs. Date shows the year strip + month scroller; Time shows Hours / Minutes.
- Date-only: the same year + month overlay, still field-width.
Desktop date+time stays side-by-side (year | month | time).
Scroll policy matches the registration dropdown:
- Desktop (fine pointer): page scroll is locked; a transparent backdrop swallows outside click / wheel.
- Mobile (coarse pointer): the page can scroll; the overlay closes on outside tap, drag, wheel, or scroll (after a short open grace so keyboard/focus scroll-into-view does not dismiss it).
Events
| Event | Payload | Notes |
|---|---|---|
update:modelValue |
string | [string, string] | null |
Emitted on selection or valid manual input |
open |
— | Overlay opened |
close |
— | Overlay closed |
Model contract (forms)
- Date only →
yyyy-MM-dd - With time →
yyyy-MM-dd'T'HH:mm
Develop
npm install
npm test
npm run build
npm run publish:pkg # requires NPM_TOKEN with @contactless publish rights (see .npmrc)
Local consumer wiring before first publish:
"@contactless/vue-datepicker": "file:../../vue-datepicker"
Theming
Override CSS variables on .cl-dp / :root:
--cl-dp-accent,--cl-dp-bg,--cl-dp-fg,--cl-dp-border,--cl-dp-radius, …
Version History
| Version | Released | Vue | License |
|---|---|---|---|
| 0.4.12 | ^3.5.0 | Custom | |
| 0.4.11 | ^3.5.0 | Custom | |
| 0.4.10 | ^3.5.0 | Custom | |
| 0.4.9 | ^3.5.0 | Custom | |
| 0.4.7 | ^3.5.0 | Custom | |
| 0.4.6 | ^3.5.0 | Custom | |
| 0.4.5 | ^3.5.0 | Custom | |
| 0.4.3 | ^3.5.0 | Custom | |
| 0.4.2 | ^3.5.0 | Custom | |
| 0.4.1 | ^3.5.0 | Custom | |
| 0.4.0 | ^3.5.0 | Custom | |
| 0.3.4 | ^3.5.0 | Custom | |
| 0.3.3 | ^3.5.0 | Custom | |
| 0.3.2 | ^3.5.0 | Custom | |
| 0.2.0 | ^3.5.0 | Custom | |
| 0.1.1 | ^3.5.0 | Custom | |
| 0.1.0 | ^3.5.0 | Custom |