Keyboard shortcut: Ctrl + K
Get started

Time picker

An inline clock face, the hour and minute counterpart of VDatePicker. Its value is always a 24-hour HH:mm string, whichever clock is displayed.

Usage

vue
<script setup lang="ts">
import { ref } from 'vue'
import { VTimePicker } from 'vectis-ui'

const time = ref<string | null>('09:30')
</script>

<template>
  <VTimePicker v-model="time" />
</template>

Examples

Minute step

minuteStep is the interval the hand snaps to and the arrow keys move by, on the minutes alone. The face prints only the minutes the step reaches.

vue
Every minute, the default
Quarter hours
<script setup lang="ts">
import { ref } from 'vue'
import { VTimePicker, VTypography } from 'vectis-ui'

const anyMinute = ref<string | null>('09:37')
const quarters = ref<string | null>('09:45')
</script>

<template>
  <div class="row">
    <div class="group">
      <VTypography variant="overline" tone="muted">Every minute, the default</VTypography>
      <VTimePicker v-model="anyMinute" />
    </div>

    <div class="group">
      <VTypography variant="overline" tone="muted">Quarter hours</VTypography>
      <VTimePicker v-model="quarters" :minute-step="15" />
    </div>
  </div>
</template>

<style scoped>
.row {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: var(--vectis-space-6);
}
.group {
  display: grid;
  gap: var(--vectis-space-2);
}
</style>

What may be chosen

min and max are two inclusive bounds written as canonical HH:mm strings, and allowedHours and allowedMinutes each take the list of values they allow or a rule answering for one. What they rule out is left off the face, and an hour is closed only when nothing at all is left in it.

vue
Between 09:30 and 17:00

Nine o'clock stays open, and it is its first thirty minutes that go

Quarter hours, on three hours

The face keeps only the five minute marks a rule leaves standing

<script setup lang="ts">
import { ref } from 'vue'
import { VTimePicker, VTypography } from 'vectis-ui'

const office = ref<string | null>('09:30')
const booking = ref<string | null>('14:15')
</script>

<template>
  <div class="row">
    <div class="group">
      <VTypography variant="overline" tone="muted">Between 09:30 and 17:00</VTypography>
      <VTimePicker v-model="office" format="24h" min="09:30" max="17:00" />
      <VTypography variant="caption" tone="muted">
        Nine o'clock stays open, and it is its first thirty minutes that go
      </VTypography>
    </div>

    <div class="group">
      <VTypography variant="overline" tone="muted">Quarter hours, on three hours</VTypography>
      <VTimePicker
        v-model="booking"
        format="24h"
        :minute-step="5"
        :allowed-hours="[9, 14, 16]"
        :allowed-minutes="(minute) => minute % 15 === 0"
      />
      <VTypography variant="caption" tone="muted">
        The face keeps only the five minute marks a rule leaves standing
      </VTypography>
    </div>
  </div>
</template>

<style scoped>
.row {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: var(--vectis-space-6);
}
.group {
  display: grid;
  gap: var(--vectis-space-2);
  max-inline-size: 20rem;
}
</style>

Hour format

format picks between a 12-hour face, one ring of numerals with the AM and PM pair beside them, and a 24-hour face, two rings and no pair. Left out, the reader's language decides. The value is the same either way.

vue
format 12h
format 24h
<script setup lang="ts">
import { ref } from 'vue'
import { VTimePicker, VTypography } from 'vectis-ui'

/* Two faces, one value: half past seven in the evening is 19:30 on either of them. */
const twelve = ref<string | null>('19:30')
const twentyFour = ref<string | null>('19:30')
</script>

<template>
  <div class="row">
    <div class="group">
      <VTypography variant="overline" tone="muted">format 12h</VTypography>
      <VTimePicker v-model="twelve" format="12h" />
    </div>

    <div class="group">
      <VTypography variant="overline" tone="muted">format 24h</VTypography>
      <VTimePicker v-model="twentyFour" format="24h" />
    </div>
  </div>
</template>

<style scoped>
.row {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: var(--vectis-space-6);
}
.group {
  display: grid;
  gap: var(--vectis-space-2);
}
</style>

Localization

locale decides the clock here: a language counting in twelve hours gets the single ring, one counting in twenty-four the double ring. It takes precedence over the global locale and falls back to it. The wording comes from the dictionary.

vue
en-US, twelve hours
en-GB, twenty-four
ja-JP
<script setup lang="ts">
import { ref } from 'vue'
import { VTimePicker, VTypography } from 'vectis-ui'

/* Each keeps its own value, so adjusting one does not disturb the others. en-US and en-GB
   are the sharp pair: the same words, and only the clock between them. */
const locales = ref<{ tag: string; caption: string; time: string | null }[]>([
  { tag: 'en-US', caption: 'en-US, twelve hours', time: '19:30' },
  { tag: 'en-GB', caption: 'en-GB, twenty-four', time: '19:30' },
  { tag: 'ja-JP', caption: 'ja-JP', time: '19:30' },
])
</script>

<template>
  <div class="row">
    <div v-for="locale in locales" :key="locale.tag" class="group">
      <VTypography variant="overline" tone="muted">{{ locale.caption }}</VTypography>
      <VTimePicker v-model="locale.time" :locale="locale.tag" />
    </div>
  </div>
</template>

<style scoped>
.row {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: var(--vectis-space-6);
}
.group {
  display: grid;
  gap: var(--vectis-space-2);
}
</style>

API

Props

PropTypeDefault
formatTimePickerFormat'12h' | '24h'none
Whether the face shows a 12- or a 24-hour clock. Left out, the reader's language decides, which is almost always what one wants.
localestringnone
A BCP 47 locale, which decides the clock. It takes precedence over the design system's global locale and falls back to it, which is why it has no literal default.
minuteStepnumber1
The interval the minutes snap to, both when dragging and with the arrow keys. The face prints only the minutes it can reach, so a step of a quarter of an hour marks four.
minstringnone
The earliest time that can be chosen, inclusive, as a canonical 24-hour string. The face leaves off what falls outside it, the way it leaves off the minutes the step cannot reach.
maxstringnone
The latest time that can be chosen, inclusive, written like min.
allowedHoursTimePickerAllowednone
Which hours can be chosen: the list of them, or a rule answering for one. The hour a rule is handed is always the 24-hour one, whichever clock is on display. The hours it leaves out are not printed.
allowedMinutesTimePickerAllowednone
Which minutes can be chosen: the list of them, or a rule answering for one. The minutes it leaves out are not printed.
disabledbooleanfalse
Makes the whole clock unusable: the hand cannot be moved, the half-day cannot be changed, and everything greys out through the colour tokens.
readonlybooleanfalse
Shows the time without letting it be changed. The face keeps its focus and the two numerals still switch between the hour and the minutes, so the value can be read in full.
labelstringnone
The accessible name of the whole clock, its two numerals and its face together. It falls back to the dictionary, and a consumer aria-label wins over it. The face keeps its own name, which says whether the hand is on the hour or the minutes.
v-modelstring | nullnull
The time, always as a 24-hour string whatever clock is displayed, so you never have to know which one the language uses. With no value the clock shows midnight rather than the current time: reading the clock while rendering would make a page drawn on a server disagree with the same page in the browser.

Events

EventType
confirm[value: string | null]
The reader has finished, with the time as it stands: the minutes were settled from the keyboard. Releasing a pointer is how one stops adjusting the hand, not how one confirms, so it does not fire. Where VDatePicker's select says a date was chosen, this says the choosing is over.

Slots

SlotType
footer{}
A strip at the foot of the clock, the place for actions such as Cancel and OK.

Types

The types the tables above name, written as the library declares them. The ones carrying export can be imported from vectis-ui to type your own code; the others are the shape of what a slot hands out.

export type TimePickerAllowed = number[] | ((value: number) => boolean)

CSS variables

TokenValue
--vectis-control-size-time-picker-dial16rem
--vectis-control-size-time-picker-number3rem
--vectis-control-size-time-picker-center0.5rem
--vectis-control-size-time-picker-hand2px
--vectis-control-size-time-picker-hand-minor1rem