CDatePicker
CDatePicker is a standalone single-date calendar. Its three views (dates, months, years) toggle by clicking the header, it is fully keyboard-driven, localized through Intl with zero bundled dictionaries, and styled with presets. For a form field with this calendar in a dropdown see CDateInput.
Basic usage
Bind the selected date with v-model — the model always emits a Date. With an empty value the calendar opens around today, but today is only marked as current, not selected. Clicking the header climbs a view up: dates → months → years; picking a year and a month walks back down.
Show code
<template>
<c-date-picker v-model="date" />
</template>
<script setup lang="ts">
import { shallowRef } from 'vue'
const date = shallowRef<Date | null>(null)
</script>Disabled and highlighted dates
disabled-dates gathers restrictions in one object — every field is optional, all of them add up:
type DisabledDates = {
from?: Date | string // everything after from
to?: Date | string // everything before to
dates?: (Date | string)[] // specific dates
days?: number[] // weekdays, 0 is Sunday
daysOfMonth?: number[]
ranges?: { from: Date | string; to: Date | string }[]
custom?: (date: DatePickerDate) => boolean
}min-date / max-date clamp the whole range — including the months and years views and the header arrows. highlighted-dates marks dates without disabling them. A custom date slot can render its own markers and icons on top of those states.
The years view defaults to a range around the current year and automatically expands to include the selected year. When set, min-date and max-date become the years-view navigation bounds.
String dates
A string like '2026-05-10' is parsed as a local calendar date without a timezone shift. Date-time strings ('2026-05-10T00:00:00Z') still go through the browser Date parser and remain timezone-sensitive.
Localization
Month and weekday names come from Intl.DateTimeFormat — any BCP-47 tag works, nothing is bundled. The locale prop takes either a tag string or a Partial<DateLocale> object that overrides the dictionary (based on en). Unknown tags safely fall back to en. monday-first starts the week on Monday.
Combining a different tag with an override goes through resolveLocale:
import { resolveLocale } from '@vueland/ui/components'
const locale = { ...resolveLocale('uz'), week: ['Ya', 'Du', 'Se', 'Ch', 'Psh', 'Ju', 'Sh'] }Custom cells
The date slot replaces a day cell and receives the parsed date with state flags. month / year do the same for their views; week, dates, months, years replace whole blocks. before-header, before-body, and footer are useful for toolbars, legends, and quick actions.
Visual Presets
preset resolves class sets from the createVuelandUI registry. Picker zones (root, display, header, week, cell) compose well with CSS variables, so the same component can become either a quiet agenda calendar or a punchy campaign widget.
Show code
<template>
<c-date-picker v-model="date" preset="datePicker.neon" :highlighted-dates="highlightedDates" />
</template>const datePickerNeon = {
base: {
root: ['radius-12'],
display: ['bg-indigo', 'text-white'],
header: ['bg-grey-lighten-4'],
week: ['text-indigo'],
cell: ['radius-8'],
},
months: { cell: ['radius-10'] },
years: { cell: ['radius-10'] },
}Keyboard
A standalone calendar is focusable as a whole (tabindex="0"); inside CDateInput focus stays in the field and keys arrive through the keyboard loop.
← / →↑ / ↓Home / EndEnter / SpaceThe cursor appears on the first arrow press — on the selected date or today. Crossing a month boundary flips the table, crossing a years page flips the page; the cursor walks over disabled dates but Enter won't select them.
API
Props
modelValueDate | string | nullDatelocalestring | Partial<DateLocale>'en'monday-firstbooleanfalsedisabled-datesDisabledDateshighlighted-dates(Date | string)[]min-dateDate | stringmax-dateDate | stringpresetstringdatePicker.softEvents
update:modelValueDateSlots
before-header, before-body and footer receive the shared slot api — the same methods the internal render uses:
type DatePickerSlotApi = {
view: 'dates' | 'months' | 'years'
value: string
selected: DatePickerDate | null
disablePrev: boolean
disableNext: boolean
preset: Record<CDatePickerZone, string[]>
showNextPage(): void
showPreviousPage(): void
toggleView(): void
showToday(): void
}before-headerDatePickerSlotApibefore-bodyDatePickerSlotApifooterDatePickerSlotApiweek{ days: DatePickerWeekDay[] }dates{ dates: DatePickerEnrichedDate[], onSelect }dateDatePickerDate & { isSelected, isToday }months{ months: DatePickerEnrichedMonth[] }monthDatePickerEnrichedMonthyears{ years: DatePickerEnrichedYear[] }yearDatePickerEnrichedYearPresets
Picker zones: root, display, header, week, cell. States are the active view: dates, months, years. A preset works standalone via a registry path and nests into an input preset as the datePicker field — CDateInput picks it up through context.
Helpers
import { dateToFormatString, resolveLocale } from '@vueland/ui/components'
resolveLocale('de') // DateLocale built from Intl, cached
dateToFormatString(date, 'dd.MM.yyyy', 'ru')Format tokens: yyyy, yy, MMMM, MMM, MM, M, dd, d, D (weekday).
CSS Variables
--c-date-picker-width320px--c-date-picker-display-bgvar(--c-sys-color-primary)--c-date-picker-header-bgvar(--c-sys-color-surface-container)--c-date-picker-body-bgvar(--c-sys-color-surface)--c-date-picker-cell-sizevar(--c-sys-control-height-md)--c-date-picker-selected-bgvar(--c-sys-color-primary-container)--c-date-picker-selected-colorvar(--c-sys-color-on-primary-container)--c-date-picker-today-colorvar(--c-sys-color-primary)--c-date-picker-current-border-colorvar(--c-sys-color-primary)--c-date-picker-highlighted-bgvar(--c-sys-state-selected-color)--c-date-picker-highlighted-colorvar(--c-sys-color-primary)--c-date-picker-disabled-colorvar(--c-sys-color-disabled)--c-date-picker-focus-ring-colorvar(--c-sys-color-primary)