Vue Time Picker Component

Time Picker

CoreUI PRO
This component is part of CoreUI PRO – a powerful UI library with over 250 components and 25+ templates, designed to help you build modern, responsive apps faster. Fully compatible with Angular, Bootstrap, React.js, and Vue.js.

The Vue Time Picker Component offers a seamless way for users to select time values in any Vue-based application.

Available in Other JavaScript Frameworks

CoreUI Vue Time Picker Component is also available for Angular, Bootstrap, and React. Explore framework-specific implementations below:

Example

To create a basic Vue Time Picker, use:

vue
<template>
  <div class="row">
    <div class="col-sm-6 col-lg-5 mb-4 mb-sm-0">
      <CTimePicker label="Time" locale="en-US" />
    </div>
    <div class="col-sm-6 col-lg-5">
      <CTimePicker label="Time" locale="en-US" time="02:17:35 PM" />
    </div>
  </div>
</template>

<script setup>
import { CTimePicker } from '@coreui/vue-pro'
</script>

With v-model

The v-model:time binding keeps the selected time in sync with your component’s state.

vue
<template>
  <div class="row mb-4">
    <div class="col-lg-6">
      <CTimePicker v-model:time="vTime" label="Time" locale="en-US" />
    </div>
  </div>
  <div>{{ vTime }}</div>
</template>

<script setup>
import { CTimePicker } from '@coreui/vue-pro'
import { ref } from 'vue'
const vTime = ref('02:17:35 PM')
</script>

The footer slot projects your own content below the time selection. Its slot props carry the picker’s context — setTime, now, clear, reset, close, isTimeSelectable, time and disabled — so a projected button acts on the picker and reads its state. That is also how a “Now” button disables itself when the current time falls outside minDate or maxDate; the example checks when the panel renders and again on click, so a time that crosses a limit while the panel is open is not written.

Any descendant can reach the same context with the useTimePicker() composable.

vue
<template>
  <div class="row">
    <div class="col-lg-4">
      <CTimePicker locale="en-US" max-date="17:00" min-date="09:00">
        <template #footer="{ clear, close, isTimeSelectable, now }">
          <CButton
            class="me-auto"
            theme="danger"
            :disabled="!isTimeSelectable(new Date())"
            size="sm"
            variant="ghost"
            @click="isTimeSelectable(new Date()) && now()"
          >
            Now
          </CButton>
          <CButton theme="primary" size="sm" variant="ghost" @click="clear">Clear</CButton>
          <CButton theme="primary" size="sm" @click="close">OK</CButton>
        </template>
      </CTimePicker>
    </div>
  </div>
</template>

<script setup>
import { CButton, CTimePicker } from '@coreui/vue-pro'
</script>

With form field

Wrap the control in <CFormField> to lay it out with its label and description, and to get validation feedback in the right place.

A native reset of the form returns the picker to the time it started with and drops the state a submit set; a picker bound with v-model:time asks for the time it started with through update:time and time-change and shows the time your page gives until the page takes it.

vue
<template>
  <CFormField>
    <span class="form-label">Meeting time</span>
    <CTimePicker locale="en-US" name="meetingTime" />
    <CFormText>Local time, in your own time zone.</CFormText>
  </CFormField>
</template>

<script setup>
import { CFormField, CFormText } from '@coreui/vue'
import { CTimePicker } from '@coreui/vue-pro'
</script>

Floating labels

Set floatingLabel and the component wraps its input in .form-floating and renders the label itself — the text also becomes the field’s accessible name. No wrapper markup is needed, and the mask placeholders stay hidden while the label rests inside the field.

vue
<template>
  <CTimePicker floating-label="Meeting time" locale="en-US" />
</template>

Set floatingLabelAlways to keep the label always floating with the mask showing.

Sizing

Set heights using size property like size="lg" and size="sm".

vue
<template>
  <div class="row">
    <div class="col-lg-4 mb-4">
      <CTimePicker locale="en-US" size="lg" />
    </div>
  </div>
  <div class="row">
    <div class="col-lg-3">
      <CTimePicker locale="en-US" size="sm" />
    </div>
  </div>
</template>

<script setup>
import { CTimePicker } from '@coreui/vue-pro'
</script>

Theme variants

A .theme-* class on the picker colours the selected cell of every roll.

vue
<template>
  <div class="row">
    <div class="col-lg-5">
      <CTimePicker class="theme-success" label="Time" locale="en-US" time="02:30:00 PM" />
    </div>
  </div>
</template>

<script setup>
import { CTimePicker } from '@coreui/vue-pro'
</script>

Disabled

Add the disabled boolean attribute on an input to give it a grayed out appearance and remove pointer events.

vue
<template>
  <div class="row">
    <div class="col-lg-4">
      <CTimePicker disabled locale="en-US" />
    </div>
  </div>
</template>

<script setup>
import { CTimePicker } from '@coreui/vue-pro'
</script>

Readonly

Add the readOnly boolean attribute to prevent modification of the field’s value. The time selection still opens, so the value can be read but not typed over.

vue
<template>
  <div class="row">
    <div class="col-lg-4">
      <CTimePicker read-only locale="en-US" />
    </div>
  </div>
</template>

<script setup>
import { CTimePicker } from '@coreui/vue-pro'
</script>

Min and max times

Constrain the times the user can pick with min-date and max-date, given as time strings like '09:30' or as dates, of which only the time of day counts. The panel disables the hours that hold no allowed time and, once an hour is chosen, the minutes and seconds outside the range, and a time picked in the panel that crosses a limit moves to it. A time typed in the field outside the range gets the .is-invalid class, the picker emits update:time with null and submits no time until the value is corrected. A maxDate at midnight covers the whole day; any other maxDate before the minDate leaves no time to pick.

vue
<template>
  <div class="row">
    <div class="col-lg-4">
      <CTimePicker
        label="Opening hours (09:30–17:00)"
        locale="en-GB"
        max-date="17:00"
        min-date="09:30"
        :seconds="false"
      />
    </div>
  </div>
</template>

<script setup>
import { CTimePicker } from '@coreui/vue-pro'
</script>

Validation

The picker takes its validation state the way the date picker does: validationState gives 'valid', 'invalid' or a state you added to $form-validation-states, with invalid and valid as deprecated aliases that ask to be dropped the same way, though only a validation-state bound with v-model:validation-state is cleared by it. When the user changes the time, with a time picked in the panel, the cleaner, a footer button that changes the time through the context, or typing in the field, or the form is reset, the picker emits update:validationState with undefined before time-change, so bind it with v-model:validation-state, while a change your code makes through time emits nothing. While the given state is 'invalid', the sections of the field carry aria-invalid="true", are described by the message after the picker, and the picker blocks the submit with its text, or Invalid value. when there is none.

vue
<template>
  <CForm class="row g-4" novalidate validate>
    <div class="col-lg-4">
      <CTimePicker
        feedback-invalid="Please provide a meeting time."
        label="Meeting time (required)"
        locale="en-US"
        name="meeting"
        required
      />
    </div>
    <div class="col-lg-4">
      <CTimePicker
        v-model:validation-state="roomState"
        feedback="The room is taken at this time."
        label="Room booking"
        locale="en-US"
        name="room"
        time="12:30:00"
      />
    </div>
    <div class="col-12">
      <CButton color="primary" type="submit">Submit</CButton>
    </div>
  </CForm>
</template>

<script setup>
import { ref } from 'vue'
import { CButton, CForm, CTimePicker } from '@coreui/vue-pro'

const roomState = ref('invalid')
</script>

Custom formats

Disable minutes and seconds

Customize Vue Time Picker to display only hours, or hours and minutes by disabling minutes/seconds.

vue
<template>
  <div class="row">
    <div class="col-sm-6 col-lg-5 mb-4 mb-sm-0">
      <CTimePicker label="Only hours and minutes" locale="en-US" :seconds="false" />
    </div>
    <div class="col-sm-6 col-lg-5">
      <CTimePicker label="Only hours" locale="en-US" :minutes="false" :seconds="false" />
    </div>
  </div>
</template>

<script setup>
import { CTimePicker } from '@coreui/vue-pro'
</script>

Custom hours, minutes and seconds

Tailor the Vue Time Picker to your needs by specifying custom values for hours, minutes, and seconds. Use arrays to define selectable options or functions for dynamic filtering. Hours are 0 to 23 in every locale. On a 12-hour clock the column still lists 1 to 12 next to AM/PM: picking an hour that only one period allows sets that period, and the period the picked hour does not allow is disabled, so the example below offers 8 AM to 4 PM, minutes in quarters and seconds under 20.

vue
<template>
  <div class="row">
    <div class="col-sm-6 col-lg-5">
      <CTimePicker
        locale="en-US"
        :hours="[8, 9, 10, 11, 12, 13, 14, 15, 16]"
        :minutes="[0, 15, 30, 45]"
        :seconds="(s) => s < 20"
      />
    </div>
  </div>
</template>

<script setup>
import { CTimePicker } from '@coreui/vue-pro'
</script>

Locale

Tailor the Vue Time Picker to match different locales, offering an inclusive user experience across diverse languages. Automatically adapt or set specific locales to meet your application’s needs.

The locale decides whether the field and the time columns use a 12-hour or a 24-hour clock, and names the day periods in its own words, 오전 and 오후 in Korean. A format pins the clock in every locale, 'HH:mm' for 24 hours and 'hh:mm a' for 12.

Auto

Our Time Picker component automatically detects and adapts to the user’s locale, ensuring a localized experience without explicit configuration.

With server-side rendering, pass locale explicitly: by default the server writes the text in its own locale and the browser in the reader’s, and Vue reports a hydration mismatch when the two differ.

vue
<template>
  <div class="row">
    <div class="col-lg-4">
      <CTimePicker />
    </div>
  </div>
</template>

<script setup>
import { CTimePicker } from '@coreui/vue-pro'
</script>

Chinese

Specify the locale to Chinese (zh-CN) for users in China, enhancing usability with a familiar format and language.

vue
<template>
  <div class="row">
    <div class="col-lg-4">
      <CTimePicker label="入住日期" locale="zh-CN" />
    </div>
  </div>
</template>

<script setup>
import { CTimePicker } from '@coreui/vue-pro'
</script>

Japanese

Set the Time Picker’s locale to Japanese (ja) to cater to Japanese users, presenting date and time in a localized format.

vue
<template>
  <div class="row">
    <div class="col-lg-4">
      <CTimePicker label="日付を選択" locale="ja" />
    </div>
  </div>
</template>

<script setup>
import { CTimePicker } from '@coreui/vue-pro'
</script>

Korean

Configure the locale to Korean (ko) for a tailored experience in Korea, offering date and time selection in the local language.

vue
<template>
  <div class="row">
    <div class="col-lg-4">
      <CTimePicker label="날짜 선택" locale="ko" />
    </div>
  </div>
</template>

<script setup>
import { CTimePicker } from '@coreui/vue-pro'
</script>

This approach ensures that our Vue TimePicker component is versatile and adaptable, providing a seamless and intuitive interface for users worldwide.

Right to left support

RTL support is built-in and can be explicitly controlled through the $enable-rtl variables in scss.

Hebrew

vue
<template>
  <div class="row" dir="rtl">
    <div class="col-lg-4">
      <CTimePicker label="בחר תאריך" locale="he-IL" />
    </div>
  </div>
</template>

<script setup>
import { CTimePicker } from '@coreui/vue-pro'
</script>

Persian

vue
<template>
  <div class="row" dir="rtl">
    <div class="col-lg-4">
      <CTimePicker label="تاریخ شروع" locale="fa-IR" />
    </div>
  </div>
</template>

<script setup>
import { CTimePicker } from '@coreui/vue-pro'
</script>

Open state

Added in v6.0.0

Bind v-model:show and the panel renders what you pass — dismiss gestures only emit update:show, so the binding feeds the change back. Here a checkbox pins the panel open, and a dismiss gesture unchecks it.

vue
<template>
  <CFormField class="mb-4">
    <CCheckbox id="timePickerControlledShow" v-model="show" label="Keep the time selection open" />
  </CFormField>
  <div class="row">
    <div class="col-sm-6 col-lg-4">
      <CTimePicker v-model:show="show" label="Time" locale="en-US" />
    </div>
  </div>
</template>

<script setup>
import { ref } from 'vue'
import { CCheckbox, CFormField, CTimePicker } from '@coreui/vue-pro'
const show = ref(false)
</script>

Initial open state

Without a binding the picker manages its own panel. Pass show to seed it open on mount.

<CTimePicker show />

The update:show event fires either way whenever the panel requests an open-state change — a dismiss gesture (Escape, a click outside) or any internal toggle — so you can watch the state without taking it over. The deprecated visible prop keeps its old behavior and is ignored when show is set.

Accessibility

The field is a group of spinbutton sections, so its own arrow keys belong to the value and the panel opens on the native control’s dropdown keys instead. The field takes its name from an aria-labelledby or aria-label you pass to the picker, otherwise from floatingLabel or, without one, from label, and it is described by an aria-describedby you pass to the picker, then by text and the feedback that matches its state. Clicking the label that names the field moves focus to its first empty section. Each column of the roll is an ARIA listbox, and a roving tabindex keeps the whole body to a single tab stop, with the arrows moving between the columns. While the field is empty no option is selected, and the tab stop and each column start on their first option the limits allow.

The toggle button carries the panel’s state — aria-haspopup="dialog", aria-controls pointing at the popup while it is open, and aria-expanded — so a screen reader announces what the button does and whether the panel is showing. The panel itself is a dialog with aria-modal, so focus moves into it on open, stays there while it is open, and returns to the field when it closes.

Keyboard support

KeyAction
Alt (Option on macOS) + Arrow Down / F4Open the panel and move focus into it
EscapeClose the panel and return focus to the field
Arrow Up / Arrow DownMove between the cells of a column
Arrow Left / Arrow RightMove between the columns
Home / EndJump to the ends of a column
Enter / SpaceSelect the focused value and move to the next column

API

Check out the documentation below for a comprehensive guide to all the props you can use with the components mentioned here.