@contactless/vue-datepicker

Contactless Vue 3 datepicker
3,070
Install
npm install @contactless/vue-datepicker
Latest Version:0.4.12
Vue:3
License:Custom
Last Updated:Aug 25, 2026
Links: Bitbucket  ·  npm
Maintainer: contactless

@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