GrDateTimePicker

  • chrono
  • chrono
  • API · 32 props
import { GrDateTimePicker } from '@feugene/granularity-chrono/components/GrDateTimePicker'

Overview

When to take it

  • a moment rather than a day — the start of a meeting, a deadline, a publication time: a date without a time would mean midnight here, which the user did not have in mind;
  • a choice of several steps — the day, the hour, the minute; autoApply: false gives a confirmation, so that the value does not leave after the very first click;
  • seconds are needed — enableSeconds adds a third column;
  • a string goes to the backend — valueAdapter="isoDateTime" gives away '2026-08-12T14:30:00' with no offset: that is what a person sees on the clock.

When to take something else

NeedTake
A date onlyGrDatePicker
A time onlyGrTimePicker
A “from — to” periodGrDateRangePicker
The month grid without a fieldGrCalendar
Show a moment rather than choose oneGrRelativeTime

A period with times on the bounds is not covered by this package: GrDateRangePicker works with dates. It is assembled from two GrDateTimePicker with a check of the order on the side of the form.

Examples 3 each with a live demo and its code

  • Scheduling a reminder email

    One value holds the day and the time — two separate fields would allow a day without a time. minute-step puts the time on quarters of an hour, min is a moment — now — and value-adapter="isoDateTime" hands the API the local ISO string it stores; name sends it with a native form.

    Schedule the reminder
    Sends Wednesday 7 October at 09:00 · Northwind Traders, INV-0418
  • A cutover confirmed by a button

    auto-apply="false" keeps a draft until it is confirmed: a moment is assembled from day, hours, minutes and seconds, and applying it after the first click would schedule a half-picked answer. The footer slot names the answers, and enable-seconds is here because a price cutover really is to the second.

    Price list 2027 · cutoverScheduled
  • A home visit within moments, not days

    min and max cut moments: 8 AM tomorrow is allowed and 7:30 is not, though both are on the same day. Weekends are disabled-dates, use-12-hours follows a US reader’s habit, and format decides how the chosen moment reads in the field.

    Book a home visitBayview Clinic · Dr. Grace Wu

    Weekdays, 8 AM – 6 PM

API generated from the package · cannot drift

Props

PropTypedefaultDescription
modelValuev-modelTValue | undefinedundefinedA date with time (`v-model`). The type is set by `valueAdapter`; `null` — nothing is selected.
valueAdapter
"date" | "isoDate" | "isoDateTime" | "timestamp" | GrChronoA"date" | "isoDate" | "isoDateTime" | "timestamp" | GrChronoAdapter<TValue> | undefined
undefinedHow the value is emitted and comes back: the name of a built-in adapter (`date`, `isoDate`, `isoDateTime`, `timestamp`) or a custom one.
minDate | undefinedundefinedLower bound: the date by the grid, the time by the columns.
maxDate | undefinedundefinedUpper bound.
disabledDatesreadonly Date[] | ((date: Date) => boolean) | undefinedundefinedForbidden dates: a list or a predicate.
weekStartIsoWeekday | undefinedundefinedFirst day of the week per ISO (1 is Monday). Not set — from the locale.
showWeekNumbersboolean | undefinedundefinedA column of ISO 8601 week numbers in the panel. Not set — the `GrCalendar` setting from `GrConfigProvider`, otherwise `false`.
minuteStepnumber | undefined1Step of the minutes column, in minutes. `1` by default.
secondStepnumber | undefined1Step of the seconds column, in seconds. `1` by default; meaningful with `enableSeconds`.
enableSecondsboolean | undefinedfalseA seconds column in the panel and seconds in the field. Off by default.
use12Hoursboolean | undefinedundefined12-hour view of the columns. Not set — from the locale via `Intl`.
autoApplyboolean | undefinedtrueEvery step is emitted right away. `false` — the panel edits a draft, and the model changes on the confirm button.
todayDate | undefinedundefinedWhat counts as today. Set for the sake of reproducible tests.
formatIntl.DateTimeFormatOptions | undefinedundefinedHow the value looks in the field — via `Intl` options, not a pattern string.

Slots

SlotTypeDescription
day{ cell: CalendarCell; selected: boolean; }A custom day cell instead of the number.
header{ title: string; goToPeriod: (delta: number) => void; }A custom grid header instead of the title and the arrows.
weekday{ label: string; full: string; isoWeekday: IsoWeekday; }A custom weekday header cell instead of the abbreviated day name.
footer{ apply: () => void; cancel: () => void; }The panel footer instead of the confirm buttons.

Events

EventSignatureDescription
update:modelValue(e: "update:modelValue", value: TValue | null): voidThe new value (`v-model`); `null` — the value was removed.
change(e: "change", value: TValue | null): voidThe value was committed: by a selection in the panel, by typing or by clearing.
update:open(e: "update:open", value: boolean): voidThe panel opened or closed (`v-model:open`).
clear(e: "clear"): voidThe value was removed with the clear button; only with `clearable`.
focus(e: "focus", event: FocusEvent): voidFocus entered the field.
blur(e: "blur", event: FocusEvent): voidFocus left the field.

Types

Every exported type of the subpath, grouped by the file it lives in. Names, generics and bodies come from the package’s declaration files and cannot drift.

Import
import type { GrDateTimePickerConfigurableProps, GrDateTimePickerSize, GrDateTimePickerProps } from '@feugene/granularity-chrono/components/GrDateTimePicker'

Filedist/types/components/GrDateTimePicker/config.d.ts

grDateTimePickerConfigconst
const grDateTimePickerConfig: import("@feugene/granum/contract").GranumComponentDescriptor<"GrDateTimePicker">;

Filedist/types/components/GrDateTimePicker/defaults.d.ts

GrDateTimePickerConfigurablePropsinterface
interface GrDateTimePickerConfigurableProps {
    size: GrDateTimePickerSize;
    clearable: boolean;
    placement: UseFloatingPlacement;
}

Filedist/types/components/GrDateTimePicker/grDateTimePickerStyles.d.ts

GrDateTimePickerSizetype
type GrDateTimePickerSize = GrPickerSize;

Filedist/types/components/GrDateTimePicker/safelist.d.ts

grDateTimePickerSafelistconst
const grDateTimePickerSafelist: string[];

Filedist/types/components/GrDateTimePicker/GrDateTimePicker.vue.d.ts

GrDateTimePickerPropsinterface
interface GrDateTimePickerProps<T = Date | null> {
    modelValue?: T;
    valueAdapter?: GrChronoAdapterName | GrChronoAdapter<T>;
    min?: Date;
    max?: Date;
    disabledDates?: readonly Date[] | ((date: Date) => boolean);
GrDateTimePickerEmitsinterface
interface GrDateTimePickerEmits<T = Date | null> {
    (e: 'update:modelValue', value: T | null): void;
    (e: 'change', value: T | null): void;
    (e: 'update:open', value: boolean): void;
    (e: 'clear'): void;
    (e: 'focus', event: FocusEvent): void;
    (e: 'blur', event: FocusEvent): void;
}

Usage from the library prose

autoApply means something different here than in a date picker

When a single date is chosen, a click on a day is the finished value, and there is nothing to confirm. Here the value is assembled from at least two parts, so “apply” means “I am done” rather than repeating what has already been done. The default is true: a date plus an hour is usually enough, and an extra button on every choice is irritating.

Typing

editable switches on entry from the keyboard: one string sets both the date and the time.

vue
<GrDateTimePicker v-model="startsAt" editable />

The parsing goes from Intl: where in the string the date is and where the time, what order the parts are in and what separates them is known by the locale rather than by a pattern. It can therefore be typed however is convenient — 8/14/2026 10:15, 8/14/2026, 10:15, 08.14.2026 10:15: the separators are irrelevant to the parsing, which looks at the groups of digits. Locales in which the time goes before the date (vi — 15:30 12/8/26) are parsed the same way.

A typed date without a time does not reset the time — what stands in the model remains; with an empty model that is midnight. What was not typed simply does not change.

Text confirms itself, bypassing autoApply. The prop governs the panel, where the choice is multi-step and “apply” means “I am done”. Enter in the field is already a finished action, and going into a draft would look like “nothing happened”: the field does show the model.

The panel follows the typing. As soon as the date has been typed in full, it is highlighted in the grid and the grid has moved to its month; the typed hour is highlighted in the column of hours, the minutes in the minutes. The model does not change in the process: it is changed by Enter or by the loss of focus. Typing blindly while looking at a panel with the previous value is exactly the error the field was supposed to remove.

A forbidden value is not accepted as text either — neither a date from disabledDates nor a moment past min or max. The rule is one for a click and for Enter, otherwise the field would bypass the restrictions of the panel.

Text that did not parse is rolled back to the model on the loss of focus; apply-on-blur="false" leaves the confirmation to Enter alone. The default placeholder is a hint of the format (MM/DD/YYYY, HH:MM in the letters of the locale), because the order of the parts differs by locale.

With editable the field shows the value in digits rather than as Aug 12, 2026, 09:30: the typing has to read back what is shown, otherwise editing a number right in the field would leave the parser two groups of digits instead of three and would roll back silently. A format of your own overrides that rule — then the readability is the consumer’s responsibility.

The field deliberately has no mask: it would guess the boundary between the date and the time and would get in the way of deleting.

The parsing works over the digits 0–9. Locales with digits of their own (ar-EG, fa-IR) are not supported for typing yet — the display in them is correct, but the entry has to be done with European digits.