Skip to content

feat(VTimeInput): add new component - #23141

Draft
J-Sek wants to merge 1 commit into
devfrom
feat/v-time-input
Draft

feat(VTimeInput): add new component#23141
J-Sek wants to merge 1 commit into
devfrom
feat/v-time-input

Conversation

@J-Sek

@J-Sek J-Sek commented Aug 24, 2026

Copy link
Copy Markdown
Contributor
  • guided typing
  • mobile variant: clock / digital
  • desktop variant for picker: something suitable for VDateTimePicker sidebar, similar to native picker
  • support localized dayPeriod

Markup:

<template>
  <v-app theme="dark">
    <v-container max-width="900">
      <v-row class="align-center">
        <v-col cols="12" md="auto">
          <v-btn-toggle v-model="variant" density="compact" divided mandatory>
            <v-btn v-for="v in variants" :key="v" :text="v" :value="v" size="small" />
          </v-btn-toggle>
        </v-col>

        <v-col cols="12" md="auto">
          <v-btn-toggle v-model="density" density="compact" divided mandatory>
            <v-btn v-for="d in densities" :key="d" :text="d" :value="d" size="small" />
          </v-btn-toggle>
        </v-col>

        <v-col cols="12" md="auto">
          <v-chip-group v-model="color" filter mandatory>
            <v-chip
              v-for="c in colors"
              :key="c"
              :base-color="c"
              :text="c"
              :value="c"
              label
            />
          </v-chip-group>
        </v-col>

        <v-col cols="12" md="auto">
          <v-chip-group v-model="updateOn" filter multiple>
            <v-chip text="update on blur" value="blur" label />
            <v-chip text="update on enter" value="enter" label />
          </v-chip-group>
        </v-col>
      </v-row>

      <v-row class="align-center">
        <v-col cols="6" md="4">
          <v-select
            v-model="dateFormat"
            :items="dateFormats"
            density="compact"
            label="input-format"
            clearable
            hide-details
          />
        </v-col>

        <v-col cols="6" md="4">
          <v-select
            v-model="timeFormat"
            :items="timeFormats"
            density="compact"
            label="format"
            clearable
            hide-details
          />
        </v-col>

        <v-col cols="6" md="4">
          <v-select v-model="timeInterval" :items="[15, 30, 60, 120]" density="compact" label="time-interval" hide-details />
        </v-col>

        <v-col cols="12" md="auto">
          <div class="d-flex ga-4 flex-wrap">
            <v-switch v-model="useSeconds" color="primary" density="compact" label="use-seconds" hide-details />
            <v-switch v-model="openOnFocus" color="primary" density="compact" label="open-on-focus" hide-details />
            <v-switch v-model="hideActions" color="primary" density="compact" label="hide-actions" hide-details />
            <v-switch v-model="clearable" color="primary" density="compact" label="clearable" hide-details />
            <v-switch v-model="disabled" color="primary" density="compact" label="disabled" hide-details />
            <v-switch v-model="readonly" color="primary" density="compact" label="readonly" hide-details />
          </div>
        </v-col>
      </v-row>

      <v-divider class="my-4" />

      <v-row>
        <v-col cols="12" md="6">
          <h4 class="mb-4">VDateInput</h4>

          <v-date-input v-bind="{ ...common, ...dateProps }" v-model="date1" />
          <v-chip :text="fmt(date1)" class="mb-6" size="small" />

          <v-date-input v-bind="{ ...common, ...dateProps }" v-model="date2" multiple />
          <v-chip :text="fmt(date2)" class="mb-6" size="small" />

          <v-date-input v-bind="{ ...common, ...dateProps }" v-model="date3" multiple="range" />
          <v-chip :text="fmt(date3)" class="mb-6" size="small" />

          <v-date-input
            v-bind="{ ...common, ...dateProps }"
            v-model="date4"
            max="2026-09-15"
            min="2026-08-01"
          />
          <v-chip :text="fmt(date4)" size="small" />
        </v-col>

        <v-col cols="12" md="6">
          <h4 class="mb-4">VTimeInput</h4>

          <v-time-input v-bind="{ ...common, ...timeProps }" v-model="time1" />
          <v-chip :text="fmt(time1)" class="mb-6" size="small" />

          <v-time-input v-bind="{ ...common, ...timeProps }" v-model="time2" max="17:30" min="09:00" />
          <v-chip :text="fmt(time2)" class="mb-6" size="small" />

          <v-time-input
            v-bind="{ ...common, ...timeProps }"
            v-model="time3"
            :allowed-minutes="m => m % 15 === 0"
            label="Quarters only + scrollable"
            persistent-placeholder
            scrollable
          />
          <v-chip :text="fmt(time3)" class="mb-6" size="small" />
        </v-col>
      </v-row>

      <v-divider class="my-4" />

      <v-row>
        <v-col cols="12" md="6">
          <h4 class="mb-4">RTL</h4>

          <v-locale-provider rtl>
            <v-date-input v-bind="{ ...common, ...dateProps }" v-model="date5" multiple="range" />
            <v-time-input v-bind="{ ...common, ...timeProps }" v-model="time5" />
          </v-locale-provider>
        </v-col>

        <v-col cols="12" md="6">
          <h4 class="mb-4">Korean locale</h4>

          <v-locale-provider locale="ko">
            <v-date-input v-bind="{ ...common, ...dateProps }" v-model="date5" multiple="range" />
            <v-time-input v-bind="{ ...common, ...timeProps }" v-model="time5" />
          </v-locale-provider>
        </v-col>

        <v-col cols="12" md="6">
          <h4 class="mb-4">Native</h4>

          <v-text-field v-bind="common" label="date" type="date" />
          <v-text-field v-bind="common" label="datetime-local" type="datetime-local" />
          <v-text-field v-bind="common" label="time" type="time" />
        </v-col>
      </v-row>
    </v-container>
  </v-app>
</template>

<script setup>
  import { computed, shallowRef } from 'vue'

  const variants = ['outlined', 'filled', 'solo', 'underlined']
  const densities = ['default', 'comfortable', 'compact']
  const colors = ['primary', 'success', 'purple', '#fa0']
  const dateFormats = [null, 'dd/mm/yyyy', 'mm/dd/yyyy', 'yyyy-mm-dd', 'dd.mm.yyyy'].map(x => ({ title: x ?? '(locale)', value: x }))
  const timeFormats = [null, 'ampm', '24hr'].map(x => ({ title: x ?? '(locale)', value: x }))

  const variant = shallowRef('outlined')
  const density = shallowRef('default')
  const color = shallowRef('primary')
  const dateFormat = shallowRef(null)
  const timeFormat = shallowRef(undefined)
  const timeInterval = shallowRef(30)
  const updateOn = shallowRef(['blur', 'enter'])
  const useSeconds = shallowRef(false)
  const openOnFocus = shallowRef(false)
  const hideActions = shallowRef(true)
  const clearable = shallowRef(true)
  const disabled = shallowRef(false)
  const readonly = shallowRef(false)

  const common = computed(() => ({
    variant: variant.value,
    density: density.value,
    color: color.value,
    updateOn: updateOn.value,
    openOnFocus: openOnFocus.value,
    hideActions: hideActions.value,
    clearable: clearable.value,
    disabled: disabled.value,
    readonly: readonly.value,
  }))
  const dateProps = computed(() => ({ inputFormat: dateFormat.value }))
  const timeProps = computed(() => ({ format: timeFormat.value ?? undefined, useSeconds: useSeconds.value }))
  const dateTimeProps = computed(() => ({ ...dateProps.value, ...timeProps.value, timeInterval: timeInterval.value }))

  const date1 = shallowRef(new Date(2026, 7, 19))
  const date2 = shallowRef([new Date(2026, 7, 19), new Date(2026, 7, 24)])
  const date3 = shallowRef([new Date(2026, 7, 19), new Date(2026, 7, 24)])
  const date4 = shallowRef(null)
  const date5 = shallowRef([new Date(2026, 7, 19), new Date(2026, 7, 24)])

  const time1 = shallowRef('14:30')
  const time2 = shallowRef(null)
  const time3 = shallowRef(null)
  const time5 = shallowRef('14:30')

  function fmt (value) {
    if (value == null) return 'null'
    if (Array.isArray(value)) return value.length ? value.map(fmt).join(' | ') : '[]'
    return value instanceof Date ? value.toLocaleString() : String(value)
  }
</script>

@J-Sek J-Sek self-assigned this Aug 24, 2026
@J-Sek J-Sek added C: New Component This issue would need a new component to be developed. C: VTimeInput labels Aug 24, 2026
@J-Sek J-Sek added this to the v4.3.0 milestone Aug 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

C: New Component This issue would need a new component to be developed. C: VTimeInput

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant