GrDateTimePicker

Package: @feugene/granularity-chronocompanionGroup: misc

Machine-translated from the Russian original, not yet reviewed. Read the original

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 neededenableSeconds adds a third column;
  • a string goes to the backendvalueAdapter="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.

`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 (vi15: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 09. 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.

Install

npm i @feugene/granularity-chrono

Import

import { GrDateTimePicker } from '@feugene/granularity-chrono/components/GrDateTimePicker'

API

The API for this component has not been generated yet: the showcase generator only covers the core so far. Until it does, the reference lives in the package documentation.

Examples 3

Basic

Basic
<script setup lang="ts">
import { ref } from 'vue'

// `GrDateTimePicker` подставляется авто-импортом (`unplugin-vue-components`).
const value = ref<string | null>('2026-08-12T14:30:00')
</script>

<template>
  <div class="grid max-w-[360px] gap-4">
    <!-- Сетка и колонки в одной панели: смена дня сохраняет время, смена
         времени сохраняет день. -->
    <GrDateTimePicker
      v-model="value"
      value-adapter="isoDateTime"
      :minute-step="15"
      clearable
      placeholder="Pick date and time"
      aria-label="Meeting start"
    />

    <p class="showcase-demo-text text-sm">
      <span class="opacity-70">value=</span><code>{{ value ?? '—' }}</code>
    </p>
  </div>
</template>

Confirm

Confirm
<script setup lang="ts">
import { ref } from 'vue'

// `GrDateTimePicker` подставляется авто-импортом (`unplugin-vue-components`).
const value = ref<string | null>('2026-08-12T09:00:00')
const changes = ref(0)
</script>

<template>
  <div class="grid max-w-[360px] gap-4">
    <!-- `auto-apply="false"`: панель правит черновик, а модель меняется
         кнопкой. Счётчик показывает, что до подтверждения её никто не трогал. -->
    <GrDateTimePicker
      v-model="value"
      :auto-apply="false"
      value-adapter="isoDateTime"
      :minute-step="30"
      aria-label="Appointment"
      @change="changes += 1"
    />

    <p class="showcase-demo-text text-sm">
      <span class="opacity-70">value=</span><code>{{ value ?? '—' }}</code>
      <span class="opacity-70"> · changes=</span><code>{{ changes }}</code>
    </p>
  </div>
</template>

Editable

Editable
<script setup lang="ts">
import { ref } from 'vue'

// `GrDateTimePicker` подставляется авто-импортом.

/**
 * Момент, который быстрее набрать, чем найти кликами.
 *
 * Локаль здесь не для украшения: она задаёт и порядок частей, и разделители,
 * и то, чем разбор считает набранное. Два поля рядом показывают это без слов.
 */
const TODAY = new Date(2026, 7, 12)

const ru = ref<Date | null>(new Date(2026, 7, 12, 9, 30))
const us = ref<Date | null>(new Date(2026, 7, 12, 9, 30))
</script>

<template>
  <div class="grid gap-4 justify-items-start">
    <div class="grid gap-3 sm:grid-cols-2 w-full">
      <GrDateTimePicker
        v-model="ru"
        editable
        :today="TODAY"
        locale="ru-RU"
        aria-label="Начало, русская локаль"
      />

      <GrDateTimePicker
        v-model="us"
        editable
        :today="TODAY"
        locale="en-US"
        aria-label="Start, US locale"
      />
    </div>

    <p class="showcase-demo-text text-sm opacity-70">
      Наберите дату руками: слева ждут <strong>ДД.ММ.ГГГГ</strong>, справа — <strong>MM/DD/YYYY</strong>.
      Порядок частей не зашит в компонент, его знает локаль; разделители разбору безразличны —
      точка, слэш и пробел равноценны, потому что считаются группы цифр, а не символы между ними.
    </p>

    <p class="showcase-demo-text text-sm opacity-70">
      Панель идёт за набором: дата набрана целиком — она подсвечена, и сетка перешла на её месяц;
      набран час — подсвечен час, дописаны минуты — минуты. Модель при этом не меняется, её меняет
      <strong>Enter</strong> или уход фокуса. Набирать вслепую, глядя на панель с прежним значением,
      — ровно та ошибка, которую поле и должно было убрать.
    </p>

    <p class="showcase-demo-text text-sm opacity-70">
      Наберите одну дату без времени — время останется прежним: не набранное не меняется. Наберите
      мусор и уйдите фокусом — поле вернётся к значению. Поле показывает значение цифрами именно
      потому, что их можно править на месте: с «12 авг. 2026 г.» правка числа оставила бы разбору
      две группы цифр вместо трёх и молча откатилась бы.
    </p>
  </div>
</template>

Component documentationAll components