Component
Time selector
<DomTimeSelector>A typed time field with a popover list of selectable times. Stores HH:mm by default and can display 12-hour or 24-hour labels.
Playground
Try every prop live
Time selector playground
The input stores HH:mm by default. Use timeFormat for 12-hour labels, minuteStep for generated options, and min/max to constrain selection.
Type a time or choose one from the generated list.
<script setup>
import { reactive } from 'vue';
import { DomTimeSelector } from '@getdom/studio/vue';
const data = reactive({
"modelValue": "09:30",
"id": "",
"name": "",
"label": "Meeting time",
"description": "Type a time or choose one from the generated list.",
"placeholder": "",
"required": false,
"disabled": false,
"readOnly": false,
"invalid": false,
"errors": [],
"visible": true,
"validators": [],
"validateOnBlur": true,
"chrome": "field",
"timeFormat": "24h",
"minuteStep": 15,
"min": "08:00",
"max": "18:00",
"options": [],
"showSeconds": false,
"nativeInput": true,
"registerField": true,
"popoverProps": {}
});
</script>
<template>
<DomTimeSelector
v-bind="data"
@update:modelValue="data.modelValue = $event"
/>
</template>Demo
Generated business hours
Generate a selectable list from min, max, and minuteStep while still accepting typed times.
Type a time or choose one from the generated list.
Stored value: 09:30
<script setup>
import { ref } from 'vue';
import { DomTimeSelector } from '../../../lib/vue';
const time = ref('09:30');
</script>
<template>
<div class="max-w-sm space-y-4">
<DomTimeSelector
v-model="time"
name="meeting_time"
label="Meeting time"
description="Type a time or choose one from the generated list."
:min="'08:00'"
:max="'18:00'"
:minute-step="15"
/>
<p class="rounded-xl border border-border bg-secondary px-3 py-2 text-sm text-muted-fg">
Stored value:
<code class="font-mono text-canvas-fg">{{ time || 'empty' }}</code>
</p>
</div>
</template>
Demo
12-hour labels
Display 12-hour labels with AM and PM while storing the canonical HH:mm value.
Display options in 12-hour time while storing HH:mm.
Stored value: 14:30
<script setup>
import { ref } from 'vue';
import { DomTimeSelector } from '../../../lib/vue';
const time = ref('14:30');
</script>
<template>
<div class="max-w-sm space-y-4">
<DomTimeSelector
v-model="time"
name="handoff_time"
label="Handoff time"
description="Display options in 12-hour time while storing HH:mm."
time-format="12h"
:min="'09:00'"
:max="'17:00'"
:minute-step="30"
/>
<p class="rounded-xl border border-border bg-secondary px-3 py-2 text-sm text-muted-fg">
Stored value:
<code class="font-mono text-canvas-fg">{{ time || 'empty' }}</code>
</p>
</div>
</template>
Reference
Props
Control props
| Name | Type | TS | Default | Description |
|---|---|---|---|---|
modelValue | string | string | '' | Selected time as HH:mm, or HH:mm:ss when showSeconds is enabled. |
timeFormat | '24h' | '12h' | string | '24h' | How times are displayed in the input and option list. |
minuteStep | number | number | 15 | Minute interval used to generate selectable options. |
min | string | string | '' | Minimum selectable time as HH:mm or HH:mm:ss. |
max | string | string | '' | Maximum selectable time as HH:mm or HH:mm:ss. |
options | array | Array< | [] | Optional custom time options. Use strings such as 09:30 or records with value, label, and disabled. |
showSeconds | boolean | boolean | false | Store and display seconds in addition to hours and minutes. |
nativeInput | boolean | boolean | true | Include the native input name for HTML form submission. |
registerField | boolean | boolean | true | Register with a parent form. Disable when composing this inside another form control. |
popoverProps | object | Record<string, unknown> | {} | Props passed to the inner DomPopover. Time selector defaults position to bottom-end, max width to 18rem, padding to p-2, and arrow to true. |
Field props
| Name | Type | TS | Default | Description |
|---|---|---|---|---|
id | string | string | '' | Optional ID override. By default parent forms derive the input ID from the field path using underscores. |
name | string | string | '' | Local field name. Parent forms derive the full field path and native HTML name from the form hierarchy. |
label | string | string | '' | Visible field label. |
description | string | string | '' | Optional helper copy below the field. |
placeholder | string | string | '' | Placeholder shown when the control is empty. |
required | boolean | boolean | false | Mark the field as required. |
disabled | boolean | boolean | false | Disable field interaction. |
readOnly | boolean | boolean | false | Show the value but prevent editing. |
invalid | boolean | boolean | false | Mark the field invalid. |
errors | array | object | string | Array< | [] | Validation errors for this field. |
visible | boolean | boolean | true | Show or hide the field. |
validators | array | Array<unknown> | [] | Validators attached to this field. Use functions in Vue code, or serializable records such as { name: "minLength", props: { min: 2 } } in generated schemas. |
validateOnBlur | boolean | boolean | true | Run validators when the field loses focus. |
chrome | 'field' | false | string | 'field' | Render default field chrome, or false to render only the control while keeping form state wiring. |
Auto-generated from Time selector.props and inline _edit hints.
Events
| Name | Payload | Description |
|---|---|---|
| @update:modelValue | HH:mm | Fired when a valid time is committed or selected. |
| @change | HH:mm | Fired when a valid time is committed. |
| @invalid-time | string | Fired when typed text cannot be parsed or is outside the allowed range. |
| @focus | FocusEvent | Fired when the text input receives focus. |
| @blur | FocusEvent | Fired when the text input loses focus. |
Names auto-detected from defineEmits and source emit() calls; payload and description from __doc.events when present.
Keyboard
- Alt + ArrowDownOpen the time list.
- EnterCommit the typed time when it is valid.
- EscClose the popover.
- TabMove through generated time options when the list is open.