GrTimePicker
Overview
When to take it
- a time without a date — the start of a shift, opening hours, a reminder: the day here either does not matter or is set separately;
- the time is more convenient to type —
editablegives typing from the keyboard, and the parsing goes by the locale, the 12-hour form included where it is customary; - seconds are needed —
enableSecondsadds a third column; - the step is not a minute —
minuteStepbuilds a column with the required step, and “14:07” can no longer be entered where appointments go by half-hours.
When to take something else
| Need | Take |
|---|---|
| A date together with a time | GrDateTimePicker |
| A date only | GrDatePicker |
| A “from — to” period by dates | GrDateRangePicker |
| Enter a duration rather than a moment on the clock | GrNumberInput |
| Show a duration | GrDuration |
| Several ready slots to choose from | GrSelect |
A duration is not a time. “An hour and a half” is a number with a unit rather than a moment: the
columns of hours and minutes lie about it, because 90 minutes cannot be assembled in them. It is
entered as a number and shown with GrDuration.
Examples 3 each with a live demo and its code
Opening hours, in the API’s own strings
The shop API keeps hours as
'08:00', so a smallvalue-adapterturns the string into aDatefor the picker and back — the day never leaves the component. A 15-minuteminute-stepkeeps the hours on the grid the map shows,editablelets a manager type «7:45», andminstarts the closing column half an hour after opening.Opening hours · Kiosk AltonaShown on the map and in the app · local time, Europe/Berlin- Closed
Open 63 h 30 min a weekSent to the shop API{ "mon": ["08:00", "19:00"], "tue": ["08:00", "19:00"], "wed": ["08:00", "19:00"], "thu": ["08:00", "20:30"], "fri": ["08:00", "19:00"], "sat": ["09:00", "16:00"], "sun": null }A callback in the next free slot
The time is the only question on this step, so the list stays open (
inline).minis the next free slot andmaxthe last one: past and after-hours times are not offered at all. The footer getsselectandcanSelect, so «As soon as possible» goes through the same rules and is rounded up to the grid — 11:10 becomes 11:30.0001020304050607080910111213141516171819202122230030Call me backBilling support · today, Tuesday 13 October- Number
- +49 40 1234 5678
- Topic
- Invoice INV-2041
- Time
- 14:30 – 15:00
An incident timed to the second
enable-secondsadds the third column and the seconds in the field;editabletakes a time pasted from the logs. The value is an ISO string (value-adapter="isoDateTime") with the day fromtoday,use-12-hoursfollows the clock switch, «Now» in the footer lands on the grid like any other choice, andGrDurationturns the steps into the figures the review asks for.INC-2041 · Payments webhooks delayedTimeline · today, 13 October- Time to acknowledge
- Time to resolve
- Still open
API generated from the package · cannot drift
Props
| Prop | Type | default | Description |
|---|---|---|---|
modelValuev-model | TValue | undefined | undefined | The time (`v-model`) — a `Date` whose time of day is what matters. The type is set by `valueAdapter`; `null` — nothing is selected. |
valueAdapter |
| undefined | How the value goes outward and comes back: the name of a ready adapter (`date`, `isoDate`, `isoDateTime`, `timestamp`) or your own. |
min | Date | undefined | undefined | Lower bound. Only the time of day is taken into account. |
max | Date | undefined | undefined | Upper bound. Only the time of day is taken into account. |
minuteStep | number | undefined | 1 | Step of the minutes column, in minutes. |
secondStep | number | undefined | 1 | Step of the seconds column, in seconds. |
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. Unset — from the locale via `Intl`. |
today | Date | undefined | undefined | The date the chosen time is bound to while there is no value yet. Set for the sake of reproducible tests and snapshots. |
format | Intl.DateTimeFormatOptions | undefined | undefined | The look of the value in the field — through `Intl` options, not a pattern string. |
placeholder | string | undefined | undefined | Hint in an empty field. |
editable | boolean | undefined | false | The time can be typed by hand: `9:30`, `09:30:45`, `3:30 PM`. There is deliberately no mask here — time has a single separator, and there is nothing to fill in. |
applyOnBlur | boolean | undefined | true | The parsed text goes outward 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 what sets `inline` apart 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. Unset — from the application's i18n adapter. |
id | string | undefined | undefined | Own `id` for the field. Unset — taken from `GrFormField`. |
name | string | undefined | undefined | Name for the native form: the serialized value goes out in 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 |
|---|---|---|
footer |
| Panel footer: "now", "clear". The choice is handed inward, as with the date pickers: what is forbidden comes from `min`, `max` and the step, and `readonly` forbids the choice entirely — none of these rules are visible from the outside. |
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 { GrTimePickerConfigurableProps, GrTimePickerSize, GrTimePickerProps } from '@feugene/granularity-chrono/components/GrTimePicker'Filedist/types/components/GrTimePicker/config.d.ts
const grTimePickerConfig: import("@feugene/granum/contract").GranumComponentDescriptor<"GrTimePicker">;Filedist/types/components/GrTimePicker/defaults.d.ts
interface GrTimePickerConfigurableProps {
size: GrTimePickerSize;
clearable: boolean;
placement: UseFloatingPlacement;
}Filedist/types/components/GrTimePicker/grTimePickerStyles.d.ts
type GrTimePickerSize = GrPickerSize;Filedist/types/components/GrTimePicker/safelist.d.ts
const grTimePickerSafelist: string[];Filedist/types/components/GrTimePicker/GrTimePicker.vue.d.ts
interface GrTimePickerProps<T = Date | null> {
modelValue?: T;
valueAdapter?: GrChronoAdapterName | GrChronoAdapter<T>;
min?: Date;
max?: Date;
minuteStep?: number;
secondStep?: number;
enableSeconds?: boolean;
use12Hours?: boolean;
today?: Date;
format?: Intl.DateTimeFormatOptions;
placeholder?: string;
editable?: boolean;
applyOnBlur?: boolean;
clearable?: boolean;
open?: boolean;
inline?: boolean;
placement?: UseFloatingPlacement;
teleportTo?: string | HTMLElement;
size?: GrTimePickerSize;
locale?: string;
id?: string;
name?: string;
disabled?: boolean;
readonly?: boolean;
invalid?: boolean;
required?: boolean;
loading?: boolean;
ariaLabel?: string;
}interface GrTimePickerEmits<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
The panel does not close on a selection
The hour, the minute and the period are three separate decisions, and closing after the first of them would mean the user chose a time they did not choose. That is precisely the reason the time panel behaves unlike a calendar.
The columns show the selection and move by themselves
With a panel or inline, every column settles with the selected value in the centre — right after
mounting rather than on the first action: in inline nobody opens the panel, and the column of hours
would otherwise stay on 00–05. Without a value the column settles on the first available one — with a
min of 11:30 that is 11 rather than the forbidden zero.
Only the column itself scrolls, its scrollTop. scrollIntoView does not fit here: it moves every
scrollable ancestor up to the window, and a picker below the first screen would drag the page to
itself on load and on hydration. A step with an arrow brings the cursor to the nearest edge of the
column, again without touching the page.
The value stays a Date
Even when the date does not matter, a full moment goes outside — with the date from today or from
the current value. There is no separate “time of day” type in the model: it would require arithmetic
of its own and an adapter of its own for the sake of one component. If a '14:30' string is needed,
that is a valueAdapter on the consumer’s side.
Props in this example