CDatePicker
CDatePicker — автономный календарь для выбора одной даты. Три вьюхи (дни, месяцы, годы) переключаются кликом по заголовку, полностью управляются с клавиатуры, локализуются через Intl без словарей в бандле и стилизуются пресетами. Для поля формы с этим календарём в меню есть CDateInput.
Базовое использование
Свяжите выбранную дату через v-model — наружу приходит Date. Если значение пустое, календарь открывается на сегодняшнем месяце, но сегодняшняя дата не считается выбранной. Клик по заголовку поднимает вьюху крупнее: дни → месяцы → годы; выбор года и месяца спускает обратно к дням.
Показать код
<template>
<c-date-picker v-model="date" />
</template>
<script setup lang="ts">
import { shallowRef } from 'vue'
const date = shallowRef<Date | null>(null)
</script>Запрещённые и подсвеченные даты
disabled-dates собирает ограничения в одном объекте — все поля опциональны и складываются:
type DisabledDates = {
from?: Date | string // всё, что позже from
to?: Date | string // всё, что раньше to
dates?: (Date | string)[] // конкретные даты
days?: number[] // дни недели, 0 — воскресенье
daysOfMonth?: number[] // числа месяца
ranges?: { from: Date | string; to: Date | string }[]
custom?: (date: DatePickerDate) => boolean
}min-date / max-date дополнительно ограничивают диапазон целиком — включая вьюхи месяцев и годов и стрелки заголовка. highlighted-dates помечает даты классом подсветки, не запрещая выбор. Кастомный слот date может отрисовать поверх этих состояний свои маркеры и иконки.
Вьюха годов по умолчанию показывает диапазон около текущего года и автоматически расширяет его до выбранного года. min-date и max-date, если заданы, становятся границами навигации по годам.
Показать код
<template>
<c-date-picker
v-model="date"
:min-date="minDate"
:max-date="maxDate"
:disabled-dates="disabledDates"
:highlighted-dates="highlightedDates"
/>
</template>
<script setup lang="ts">
import { shallowRef } from 'vue'
const date = shallowRef<Date>()
const today = new Date()
const shift = (days: number) =>
new Date(today.getFullYear(), today.getMonth(), today.getDate() + days)
const minDate = shift(0)
const maxDate = shift(42)
const disabledDates = {
days: [0, 6],
ranges: [{ from: shift(12), to: shift(15) }],
}
const highlightedDates = [shift(3), shift(9), shift(18)]
</script>Строковые даты
Строка вида '2026-05-10' парсится как локальная календарная дата без сдвига таймзоны. Date-time строки ('2026-05-10T00:00:00Z') идут через браузерный Date и остаются timezone-sensitive.
Локализация
Названия месяцев и дней недели строятся через Intl.DateTimeFormat — словари в бандл не входят, работает любой BCP-47 тег. Проп locale принимает либо строку-тег, либо объект Partial<DateLocale>, точечно перекрывающий словарь (база — en). Неизвестный тег безопасно падает на en. monday-first начинает неделю с понедельника.
Показать код
<template>
<c-date-picker :locale="locale" :monday-first="locale !== 'en'" />
</template>
<script setup lang="ts">
import { shallowRef } from 'vue'
const locale = shallowRef('ru')
</script>Объектная форма перекрывает только указанные поля:
<!-- en-месяцы, но своя неделя -->
<c-date-picker :locale="{ week: ['Вс', 'Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб'] }" />Комбинация «другой тег + своё переопределение» собирается через resolveLocale:
import { resolveLocale } from '@vueland/ui/components'
const locale = { ...resolveLocale('uz'), week: ['Ya', 'Du', 'Se', 'Ch', 'Psh', 'Ju', 'Sh'] }Кастомные слоты
Слот date заменяет содержимое ячейки дня и получает разобранную дату вместе с флагами состояния. Слоты month / year делают то же для своих вьюх, а week, dates, months, years заменяют целые блоки. Слоты before-header, before-body и footer подходят для тулбаров, легенд и быстрых действий.
Показать код
<template>
<c-date-picker v-model="date" :highlighted-dates="highlightedDates">
<template #date="{ date: day, isHighlighted }">
<div class="d-flex flex-column items-center">
<span>{{ day }}</span>
<span
v-if="isHighlighted"
class="bg-orange radius-pill"
style="width: 4px; height: 4px"
></span>
</div>
</template>
</c-date-picker>
</template>Визуальные пресеты
preset берёт набор классов из реестра createVuelandUI. Зоны пикера (root, display, header, week, cell) работают вместе с CSS-переменными, поэтому один и тот же компонент можно быстро превратить в спокойный agenda-календарь или яркий промо-виджет.
Показать код
<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'] },
}Клавиатура
Standalone-календарь фокусируется целиком (tabindex="0"), внутри CDateInput фокус остаётся в поле, а клавиши доезжают через клавиатурный контур.
← / →↑ / ↓Home / EndEnter / SpaceКурсор появляется с первого нажатия стрелки — на выбранной дате или сегодня. Переход за границу месяца перелистывает таблицу, за границу страницы годов — страницу; запрещённые даты курсор проходит, но Enter их не выбирает.
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 и footer получают общий слот-апи — те же методы, что использует внутренний рендер:
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[] }yearDatePickerEnrichedYearПресеты
Зоны пикера: root, display (верхний блок с датой), header, week, cell (ячейка любой вьюхи). Состояния — активная вьюха: dates, months, years. Пресет работает standalone по пути из реестра и вкладывается в пресет инпута полем datePicker — CDateInput подхватит его через контекст.
const soft: CDatePickerPreset = {
base: {
root: ['radius-12'],
display: ['bg-grey-darken-2'],
cell: ['radius-8'],
},
years: {
cell: ['radius-8', 'text-blue-grey-darken-1'],
},
}Хелперы
import { dateToFormatString, resolveLocale } from '@vueland/ui/components'
resolveLocale('de') // DateLocale из Intl, с кэшем
dateToFormatString(date, 'dd.MM.yyyy', 'ru')Токены формата: yyyy, yy, MMMM, MMM, MM, M, dd, d, D (день недели).
CSS-переменные
--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)