Date Time Picker
Choose a local date and time with coordinated field and calendar controls.
Usage
Schedule
Choose a deployment date and wall-clock time together.
Choose a deployment date and wall-clock time together.
<!-- Date Time Picker / Schedule -->
<script setup lang="ts">
import { DateTimePickerRoot, DateTimePickerAnchor, DateTimePickerDateInput, DateTimePickerTimeInput, DateTimePickerTrigger, DateTimePickerContent, DateTimePickerPreviousWeek, DateTimePickerPreviousMonth, DateTimePickerPreviousYear, DateTimePickerNextWeek, DateTimePickerNextMonth, DateTimePickerNextYear, DateTimePickerWeekViewTrigger, DateTimePickerMonthViewTrigger, DateTimePickerYearViewTrigger, DateTimePickerGrid, DateTimePickerCell, DateTimePickerMonthCell } from '@sectile/vue/date-time-picker'
import { CalendarDays } from '@lucide/vue'
const initialValue = {
date: { year: 2026, month: 8, day: 22 },
time: { hour: 9, minute: 30, second: 0, millisecond: 0 },
}
const monthNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
</script>
<template>
<DateTimePickerRoot :default-value="initialValue" v-slot="{ dates, months, view, viewMode }" class="catalog-stack catalog-temporal-picker">
<DateTimePickerAnchor class="catalog-range-fields catalog-range-fields--single">
<label class="catalog-endpoint">
<span>Date and time</span>
<span class="catalog-date-time-control">
<DateTimePickerDateInput class="catalog-input" aria-label="Date" />
<DateTimePickerTimeInput class="catalog-input catalog-time-input" aria-label="Time" />
</span>
</label>
<DateTimePickerTrigger class="catalog-picker-trigger" aria-label="Open date and time picker">
<CalendarDays :size="18" aria-hidden="true" />
</DateTimePickerTrigger>
</DateTimePickerAnchor>
<DateTimePickerContent class="catalog-popup catalog-picker-popup catalog-picker-popup--floating">
<div class="catalog-picker-toolbar">
<div class="catalog-inline">
<DateTimePickerPreviousWeek v-if="viewMode === 'week'">‹</DateTimePickerPreviousWeek>
<DateTimePickerPreviousMonth v-else-if="viewMode === 'month'">‹</DateTimePickerPreviousMonth>
<DateTimePickerPreviousYear v-else>‹</DateTimePickerPreviousYear>
<strong>{{ viewMode === 'year' ? view.year : monthNames[view.month - 1] + ' ' + view.year }}</strong>
<DateTimePickerNextWeek v-if="viewMode === 'week'">›</DateTimePickerNextWeek>
<DateTimePickerNextMonth v-else-if="viewMode === 'month'">›</DateTimePickerNextMonth>
<DateTimePickerNextYear v-else>›</DateTimePickerNextYear>
</div>
<div class="catalog-view-switch">
<DateTimePickerWeekViewTrigger>Week</DateTimePickerWeekViewTrigger>
<DateTimePickerMonthViewTrigger>Month</DateTimePickerMonthViewTrigger>
<DateTimePickerYearViewTrigger>Year</DateTimePickerYearViewTrigger>
</div>
</div>
<DateTimePickerGrid v-if="viewMode !== 'year'" class="catalog-calendar" :data-view="viewMode">
<DateTimePickerCell
v-for="day in dates.flat()"
:key="[day.year, day.month, day.day].join('-')"
:value="day"
>
{{ day.day }}
</DateTimePickerCell>
</DateTimePickerGrid>
<DateTimePickerGrid v-else class="catalog-month-grid">
<DateTimePickerMonthCell
v-for="month in months.flat()"
:key="[month.year, month.month].join('-')"
:value="month"
>
{{ monthNames[month.month - 1] }}
</DateTimePickerMonthCell>
</DateTimePickerGrid>
</DateTimePickerContent>
</DateTimePickerRoot>
</template>Morning
Choose a morning date and time as one local schedule value.
Choose a morning date and time as one local schedule value.
<!-- Date Time Picker / Morning -->
<script setup lang="ts">
import { DateTimePickerRoot, DateTimePickerAnchor, DateTimePickerDateInput, DateTimePickerTimeInput, DateTimePickerTrigger, DateTimePickerContent, DateTimePickerPreviousWeek, DateTimePickerPreviousMonth, DateTimePickerPreviousYear, DateTimePickerNextWeek, DateTimePickerNextMonth, DateTimePickerNextYear, DateTimePickerWeekViewTrigger, DateTimePickerMonthViewTrigger, DateTimePickerYearViewTrigger, DateTimePickerGrid, DateTimePickerCell, DateTimePickerMonthCell } from '@sectile/vue/date-time-picker'
import { CalendarDays } from '@lucide/vue'
const initialValue = {
date: { year: 2026, month: 8, day: 22 },
time: { hour: 9, minute: 30, second: 0, millisecond: 0 },
}
const monthNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
</script>
<template>
<DateTimePickerRoot :default-value="initialValue" v-slot="{ dates, months, view, viewMode }" class="catalog-stack catalog-temporal-picker">
<DateTimePickerAnchor class="catalog-range-fields catalog-range-fields--single">
<label class="catalog-endpoint">
<span>Date and time</span>
<span class="catalog-date-time-control">
<DateTimePickerDateInput class="catalog-input" aria-label="Date" />
<DateTimePickerTimeInput class="catalog-input catalog-time-input" aria-label="Time" />
</span>
</label>
<DateTimePickerTrigger class="catalog-picker-trigger" aria-label="Open date and time picker">
<CalendarDays :size="18" aria-hidden="true" />
</DateTimePickerTrigger>
</DateTimePickerAnchor>
<DateTimePickerContent class="catalog-popup catalog-picker-popup catalog-picker-popup--floating">
<div class="catalog-picker-toolbar">
<div class="catalog-inline">
<DateTimePickerPreviousWeek v-if="viewMode === 'week'">‹</DateTimePickerPreviousWeek>
<DateTimePickerPreviousMonth v-else-if="viewMode === 'month'">‹</DateTimePickerPreviousMonth>
<DateTimePickerPreviousYear v-else>‹</DateTimePickerPreviousYear>
<strong>{{ viewMode === 'year' ? view.year : monthNames[view.month - 1] + ' ' + view.year }}</strong>
<DateTimePickerNextWeek v-if="viewMode === 'week'">›</DateTimePickerNextWeek>
<DateTimePickerNextMonth v-else-if="viewMode === 'month'">›</DateTimePickerNextMonth>
<DateTimePickerNextYear v-else>›</DateTimePickerNextYear>
</div>
<div class="catalog-view-switch">
<DateTimePickerWeekViewTrigger>Week</DateTimePickerWeekViewTrigger>
<DateTimePickerMonthViewTrigger>Month</DateTimePickerMonthViewTrigger>
<DateTimePickerYearViewTrigger>Year</DateTimePickerYearViewTrigger>
</div>
</div>
<DateTimePickerGrid v-if="viewMode !== 'year'" class="catalog-calendar" :data-view="viewMode">
<DateTimePickerCell
v-for="day in dates.flat()"
:key="[day.year, day.month, day.day].join('-')"
:value="day"
>
{{ day.day }}
</DateTimePickerCell>
</DateTimePickerGrid>
<DateTimePickerGrid v-else class="catalog-month-grid">
<DateTimePickerMonthCell
v-for="month in months.flat()"
:key="[month.year, month.month].join('-')"
:value="month"
>
{{ monthNames[month.month - 1] }}
</DateTimePickerMonthCell>
</DateTimePickerGrid>
</DateTimePickerContent>
</DateTimePickerRoot>
</template>Controlled
Let the parent own the current value and apply accepted changes back to the component.
Let the parent own the current value and apply accepted changes back to the component.
<!-- Date Time Picker / Controlled -->
<script setup lang="ts">
import { ref } from 'vue'
import { DateTimePickerRoot, DateTimePickerAnchor, DateTimePickerDateInput, DateTimePickerTimeInput, DateTimePickerTrigger, DateTimePickerContent, DateTimePickerPreviousWeek, DateTimePickerPreviousMonth, DateTimePickerPreviousYear, DateTimePickerNextWeek, DateTimePickerNextMonth, DateTimePickerNextYear, DateTimePickerWeekViewTrigger, DateTimePickerMonthViewTrigger, DateTimePickerYearViewTrigger, DateTimePickerGrid, DateTimePickerCell, DateTimePickerMonthCell } from '@sectile/vue/date-time-picker'
import { CalendarDays } from '@lucide/vue'
const initialValue = {
date: { year: 2026, month: 8, day: 22 },
time: { hour: 9, minute: 30, second: 0, millisecond: 0 },
}
const monthNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
const value = ref(initialValue)
</script>
<template>
<DateTimePickerRoot v-model="value" v-slot="{ dates, months, view, viewMode }" class="catalog-stack catalog-temporal-picker">
<DateTimePickerAnchor class="catalog-range-fields catalog-range-fields--single">
<label class="catalog-endpoint">
<span>Date and time</span>
<span class="catalog-date-time-control">
<DateTimePickerDateInput class="catalog-input" aria-label="Date" />
<DateTimePickerTimeInput class="catalog-input catalog-time-input" aria-label="Time" />
</span>
</label>
<DateTimePickerTrigger class="catalog-picker-trigger" aria-label="Open date and time picker">
<CalendarDays :size="18" aria-hidden="true" />
</DateTimePickerTrigger>
</DateTimePickerAnchor>
<DateTimePickerContent class="catalog-popup catalog-picker-popup catalog-picker-popup--floating">
<div class="catalog-picker-toolbar">
<div class="catalog-inline">
<DateTimePickerPreviousWeek v-if="viewMode === 'week'">‹</DateTimePickerPreviousWeek>
<DateTimePickerPreviousMonth v-else-if="viewMode === 'month'">‹</DateTimePickerPreviousMonth>
<DateTimePickerPreviousYear v-else>‹</DateTimePickerPreviousYear>
<strong>{{ viewMode === 'year' ? view.year : monthNames[view.month - 1] + ' ' + view.year }}</strong>
<DateTimePickerNextWeek v-if="viewMode === 'week'">›</DateTimePickerNextWeek>
<DateTimePickerNextMonth v-else-if="viewMode === 'month'">›</DateTimePickerNextMonth>
<DateTimePickerNextYear v-else>›</DateTimePickerNextYear>
</div>
<div class="catalog-view-switch">
<DateTimePickerWeekViewTrigger>Week</DateTimePickerWeekViewTrigger>
<DateTimePickerMonthViewTrigger>Month</DateTimePickerMonthViewTrigger>
<DateTimePickerYearViewTrigger>Year</DateTimePickerYearViewTrigger>
</div>
</div>
<DateTimePickerGrid v-if="viewMode !== 'year'" class="catalog-calendar" :data-view="viewMode">
<DateTimePickerCell
v-for="day in dates.flat()"
:key="[day.year, day.month, day.day].join('-')"
:value="day"
>
{{ day.day }}
</DateTimePickerCell>
</DateTimePickerGrid>
<DateTimePickerGrid v-else class="catalog-month-grid">
<DateTimePickerMonthCell
v-for="month in months.flat()"
:key="[month.year, month.month].join('-')"
:value="month"
>
{{ monthNames[month.month - 1] }}
</DateTimePickerMonthCell>
</DateTimePickerGrid>
</DateTimePickerContent>
</DateTimePickerRoot>
</template>Floating positioning
This component uses the shared positioning engine. Use the live positioning example to change side, align, offsets, collision boundaries, strategy, and tracking while inspecting the resolved placement.
API
Vue package: @sectile/vue/temporal/date-time-picker
DateTimePickerRootDateTimePickerTriggerDateTimePickerAnchorDateTimePickerPortalDateTimePickerContentDateTimePickerGridDateTimePickerCellDateTimePickerMonthCellDateTimePickerDateTimeInputDateTimePickerDateInputDateTimePickerTimeInputDateTimePickerPreviousWeekDateTimePickerNextWeekDateTimePickerPreviousMonthDateTimePickerNextMonthDateTimePickerPreviousYearDateTimePickerNextYearDateTimePickerWeekViewTriggerDateTimePickerMonthViewTriggerDateTimePickerYearViewTrigger
Props
DateTimePickerRootProps
alignAlignment of positioned content relative to its anchor.
asElement or component rendered for this part.
asChildWhether to merge this part into its single child instead of rendering a wrapper.
avoidCollisionsWhether positioned content may flip or shift to remain visible.
collisionBoundaryBoundary used to keep positioned content visible.
collisionPaddingSpace kept between positioned content and its collision boundary.
defaultHighlightedValueInitially highlighted value for uncontrolled state.
defaultOpenInitial uncontrolled open state.
defaultValueInitial value used when the component owns its state.
defaultViewInitial calendar or picker view.
disabledWhether interaction is unavailable.
hideWhenDetachedWhether positioned content hides when its anchor leaves the layout.
highlightedValueValue currently highlighted for keyboard interaction.
labelAccessible name announced for the control.
modelValueCurrent value when state is controlled by the parent.
openWhether the associated popup or disclosure is open.
policiesBehavior policies that customize validation, movement, or selection.
positionWhether the popup is positioned relative to its trigger.
readonlyWhether the value can be inspected but not changed.
referenceDateDeterministic civil date used when a calendar has no selected or highlighted value.
requiredWhether the control must contain a valid value before submission.
sidePreferred side of the anchor for positioned content.
sideOffsetDistance between positioned content and its anchor.
strategyCSS positioning strategy used for anchored content.
trackingUpdate strategy used while anchored content is open.
DateTimePickerPartProps
asElement or component rendered for this part.
asChildWhether to merge this part into its single child instead of rendering a wrapper.
DateTimePickerPortalProps
deferWhether Teleport target resolution waits until the end of the current mount or update tick.
disabledWhether interaction is unavailable.
toTeleport target for portalled content.
Slots
DateTimePickerRootSlotProps
datesDates projected by the active view.
disabledWhether interaction is unavailable.
highlightedValueValue currently highlighted for interaction.
monthsMonths projected by the active view.
openWhether the associated popup or disclosure is open.
readonlyWhether the value can be inspected but not changed.
valueCurrent value exposed by this contract.
viewCurrent calendar anchor.
viewModeActive calendar view mode.
yearsYears projected by the active view.
DateTimePickerCellSlotProps
disabledWhether interaction is unavailable.
highlightedWhether this item is highlighted for interaction.
inRangeWhether this value lies inside the selected range.
outsideMonthWhether this date belongs to an adjacent month.
selectedWhether this item is selected.
valueCurrent value exposed by this contract.
DateTimePickerMonthCellSlotProps
disabledWhether interaction is unavailable.
highlightedWhether this item is highlighted for interaction.
inRangeWhether this value lies inside the selected range.
selectedWhether this item is selected.
valueCurrent value exposed by this contract.
Other types
DateTimePickerValueChangeHandler
type DateTimePickerValueChangeHandler = NonNullable<InstanceType<typeof DateTimePickerRoot>['$props']['onUpdate:modelValue']>DateTimePickerOpenChangeHandler
type DateTimePickerOpenChangeHandler = NonNullable<InstanceType<typeof DateTimePickerRoot>['$props']['onUpdate:open']>DateTimePickerHighlightedValueChangeHandler
type DateTimePickerHighlightedValueChangeHandler = NonNullable<InstanceType<typeof DateTimePickerRoot>['$props']['onUpdate:highlightedValue']>DateTimeValue
| Name | Type | Required |
|---|---|---|
date | DateValue | Yes |
time | TimeValue | Yes |
DateValue
| Name | Type | Required |
|---|---|---|
year | number | Yes |
month | number | Yes |
day | number | Yes |
Parts
Shared scope: [data-scope="date-time-picker"]. Combine it with a part selector to keep styles local to this component.
| Part | Selector | Role | Extra attributes |
|---|---|---|---|
date-time-input | [data-part="date-time-input"] | Edits a combined date and time value. | — |
date-input | [data-part="date-input"] | Edits the date portion of a date-time value. | — |
time-input | [data-part="time-input"] | Edits the time portion of a date-time value. | — |
anchor | [data-part="anchor"] | Provides the positioning reference for floating content. | — |
trigger | [data-part="trigger"] | Opens, closes, or activates the associated content. | — |
content | [data-part="content"] | Contains the component content shown for the active state. | — |
week-view-trigger | [data-part="week-view-trigger"] | Switches the calendar to the week view. | — |
month-view-trigger | [data-part="month-view-trigger"] | Switches the calendar to the month view. | — |
year-view-trigger | [data-part="year-view-trigger"] | Switches the calendar to the year view. | — |
previous-week | [data-part="previous-week"] | Moves to the previous week. | — |
next-week | [data-part="next-week"] | Moves to the next week. | — |
previous-month | [data-part="previous-month"] | Moves to the previous month. | — |
next-month | [data-part="next-month"] | Moves to the next month. | — |
previous-year | [data-part="previous-year"] | Moves to the previous year. | — |
next-year | [data-part="next-year"] | Moves to the next year. | — |
grid | [data-part="grid"] | Groups cells into a navigable two-dimensional structure. | — |
cell | [data-part="cell"] | Represents one navigable or selectable grid value. | — |
month-cell | [data-part="month-cell"] | Represents one selectable month. | — |
Keyboard interaction
| Key | Behavior |
|---|---|
| Arrow keys | Move the highlighted date by one day or one week. |
| Home / End | Move to the start or end of the week. |
| Page Up / Page Down | Move by one month; hold Shift to move by one year. |
| Enter / Space | Select the highlighted date. |
| Escape | Close the calendar without selecting another date. |
Accessibility
Date and time inputs remain labeled while the popup calendar uses grid semantics and an explicit trigger.
