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: falsegives a confirmation, so that the value does not leave after the very first click; - seconds are needed —
enableSecondsadds 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
| Need | Take |
|---|---|
| A date only | GrDatePicker |
| A time only | GrTimePicker |
| A “from — to” period | GrDateRangePicker |
| The month grid without a field | GrCalendar |
| Show a moment rather than choose one | GrRelativeTime |
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-stepputs the time on quarters of an hour,minis a moment — now — andvalue-adapter="isoDateTime"hands the API the local ISO string it stores;namesends it with a native form.Schedule the reminder Sends Wednesday 7 October at 09:00 · Northwind Traders, INV-0418A 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. Thefooterslot names the answers, andenable-secondsis here because a price cutover really is to the second.Price list 2027 · cutoverScheduled A home visit within moments, not days
minandmaxcut moments: 8 AM tomorrow is allowed and 7:30 is not, though both are on the same day. Weekends aredisabled-dates,use-12-hoursfollows a US reader’s habit, andformatdecides 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
| Prop | Type | default | Description |
|---|---|---|---|
modelValuev-model | TValue | undefined | undefined | A date with time (`v-model`). The type is set by `valueAdapter`; `null` — nothing is selected. |
valueAdapter |
| undefined | How the value is emitted and comes back: the name of a built-in adapter (`date`, `isoDate`, `isoDateTime`, `timestamp`) or a custom one. |
min | Date | undefined | undefined | Lower bound: the date by the grid, the time by the columns. |
max | Date | undefined | undefined | Upper bound. |
disabledDates | readonly Date[] | ((date: Date) => boolean) | undefined | undefined | Forbidden dates: a list or a predicate. |
weekStart | IsoWeekday | undefined | undefined | First day of the week per ISO (1 is Monday). Not set — from the locale. |
showWeekNumbers | boolean | undefined | undefined | A column of ISO 8601 week numbers in the panel. Not set — the `GrCalendar` setting from `GrConfigProvider`, otherwise `false`. |
minuteStep | number | undefined | 1 | Step of the minutes column, in minutes. `1` by default. |
secondStep | number | undefined | 1 | Step of the seconds column, in seconds. `1` by default; meaningful with `enableSeconds`. |
enableSeconds | boolean | undefined | false | A seconds column in the panel and seconds in the field. Off by default. |
use12Hours | boolean | undefined | undefined | 12-hour view of the columns. Not set — from the locale via `Intl`. |
autoApply | boolean | undefined | true | Every step is emitted right away. `false` — the panel edits a draft, and the model changes on the confirm button. |
today | Date | undefined | undefined | What counts as today. Set for the sake of reproducible tests. |
format | Intl.DateTimeFormatOptions | undefined | undefined | How the value looks in the field — via `Intl` options, not a pattern string. |
placeholder | string | undefined | undefined | Hint in an empty field. If it is not set and the field is editable (`editable`), the order of the date parts from the locale is shown. |
editable | boolean | undefined | false | The value can be typed by hand. Parsing goes by `Intl`: the order of the parts and the separators come from the locale, not from a pattern string. |
applyOnBlur | boolean | undefined | true | What was typed is committed on blur, not only on `Enter`. |
clearable | boolean | undefined | undefined | A clear button in the field: it removes the value and emits `clear`. Not set — from `GrConfigProvider`, otherwise `false`. |
openv-model | boolean | undefined | undefined | Controlled state of the panel (`v-model:open`). |
inline | boolean | undefined | false | The panel is rendered in place: no field, no popover. The model, the adapter and `name` stay the picker's — that is how `inline` differs from a bare `GrCalendar`, which speaks in tuples. |
placement | Placement | undefined | undefined | The side of the field at which the panel opens. Not set — from `GrConfigProvider`, otherwise `bottom-start`. |
teleportTo | string | HTMLElement | undefined | undefined | A pinpoint override of the panel's mount point. |
size | "xs" | "sm" | "md" | "lg" | undefined | undefined | The height and type size of the field on the control scale. `md` by default; taken from `GrConfigProvider`. |
locale | string | undefined | undefined | Display locale. Not set — from the application's i18n adapter. |
id | string | undefined | undefined | The field's own `id`. Not set — taken from `GrFormField`. |
name | string | undefined | undefined | Name for the native form: the serialized value is submitted as a hidden field. |
disabled | boolean | undefined | false | The field is unavailable: the panel does not open, the value does not change. Inherited from `GrFormField`. |
readonly | boolean | undefined | false | The value is visible, the panel opens, but the selection does not change. |
invalid | boolean | undefined | false | The visual and ARIA state of an error (`aria-invalid`). Inherited from `GrFormField`. |
required | boolean | undefined | false | A required field (`aria-required`). Inherited from `GrFormField`. |
loading | boolean | undefined | false | Background work: a spinner in the field and `aria-busy`. |
ariaLabel | string | undefined | undefined | The accessible name of the field when there is no visible label. Inside `GrFormField` the name comes from its `label`. |
Slots
| Slot | Type | Description |
|---|---|---|
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
| Event | Signature | Description |
|---|---|---|
update:modelValue | (e: "update:modelValue", value: TValue | null): void | The new value (`v-model`); `null` — the value was removed. |
change | (e: "change", value: TValue | null): void | The value was committed: by a selection in the panel, by typing or by clearing. |
update:open | (e: "update:open", value: boolean): void | The panel opened or closed (`v-model:open`). |
clear | (e: "clear"): void | The value was removed with the clear button; only with `clearable`. |
focus | (e: "focus", event: FocusEvent): void | Focus entered the field. |
blur | (e: "blur", event: FocusEvent): void | Focus 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 type { GrDateTimePickerConfigurableProps, GrDateTimePickerSize, GrDateTimePickerProps } from '@feugene/granularity-chrono/components/GrDateTimePicker'Filedist/types/components/GrDateTimePicker/config.d.ts
const grDateTimePickerConfig: import("@feugene/granum/contract").GranumComponentDescriptor<"GrDateTimePicker">;Filedist/types/components/GrDateTimePicker/defaults.d.ts
interface GrDateTimePickerConfigurableProps {
size: GrDateTimePickerSize;
clearable: boolean;
placement: UseFloatingPlacement;
}Filedist/types/components/GrDateTimePicker/grDateTimePickerStyles.d.ts
type GrDateTimePickerSize = GrPickerSize;Filedist/types/components/GrDateTimePicker/safelist.d.ts
const grDateTimePickerSafelist: string[];Filedist/types/components/GrDateTimePicker/GrDateTimePicker.vue.d.ts
interface GrDateTimePickerProps<T = Date | null> {
modelValue?: T;
valueAdapter?: GrChronoAdapterName | GrChronoAdapter<T>;
min?: Date;
max?: Date;
disabledDates?: readonly Date[] | ((date: Date) => boolean);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.
<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.
Props in this example