Skip to content

Programmatic Control ​

This recipe shows how to drive the picker entirely from your own buttons and application logic.

Basic control panel ​

html
<input id="tp" type="text" placeholder="--:--" />

<div class="controls">
  <button id="btn-now">Now</button>
  <button id="btn-set">Set 09:15</button>
  <button id="btn-clear">Clear</button>
  <button id="btn-get">Alert value</button>
  <button id="btn-open">Open</button>
  <button id="btn-close">Close</button>
  <button id="btn-toggle">Toggle</button>
</div>
ts
import { Timepicker } from '@tito10047/vanilla-js-timepicker'
import '@tito10047/vanilla-js-timepicker/dist/timepicker.css'

const tp = new Timepicker('#tp', {
  onChange: (v) => console.log('onChange:', v),
  onInvalid: (e) => console.warn('invalid:', e.message),
})

document.getElementById('btn-now')!.addEventListener('click', () => tp.setNow())
document.getElementById('btn-set')!.addEventListener('click', () => tp.setValue('09:15'))
document.getElementById('btn-clear')!.addEventListener('click', () => tp.clear())
document.getElementById('btn-get')!.addEventListener('click', () => alert(tp.getValue()))
document.getElementById('btn-open')!.addEventListener('click', () => tp.open())
document.getElementById('btn-close')!.addEventListener('click', () => tp.close())
document.getElementById('btn-toggle')!.addEventListener('click', () => tp.toggle())

Reading the value from a form ​

ts
form.addEventListener('submit', (e) => {
  e.preventDefault()
  const time = tp.getValue()   // "" if empty
  const date = tp.getDate()    // Date | null

  if (!time) {
    showError('Please select a time')
    return
  }

  submitData({ time, hours: date!.getHours(), minutes: date!.getMinutes() })
})

Pre-filling from a stored value ​

ts
const savedTime = localStorage.getItem('departure') ?? ''

const tp = new Timepicker('#departure', {
  value: savedTime || null,
  onChange: (v) => localStorage.setItem('departure', v),
})

Resetting the picker ​

ts
async function resetForm() {
  await tp.clear()               // clears the value
  tp.setOptions({ minTime: '' }) // reset any dynamic constraints
}

Checking state before navigation ​

ts
nextStepBtn.addEventListener('click', async () => {
  if (!await tp.isValid()) {
    tp.focus()  // bring the user back to the input
    return
  }
  goToNextStep()
})

Setting a value from a Date object ​

ts
const meeting = new Date('2026-08-01T14:30:00')
await tp.setValue(meeting)
console.log(tp.getValue())  // "14:30"

Listening for changes via the DOM event ​

Useful in frameworks that prefer DOM event delegation:

ts
document.querySelector('#tp')!.addEventListener('vtp:change', (e) => {
  const { value, prev } = (e as CustomEvent).detail
  console.log(`Changed: ${prev} → ${value}`)
})

Dynamically updating options ​

ts
// Switch from 24-hour to 12-hour at runtime:
tp.setOptions({ format: 'hh:mm a' })

// Change the minuteStep:
tp.setOptions({ minuteStep: 1 })

The new options take effect the next time the dropdown opens. The input value is not re-formatted automatically — call setValue(tp.getValue()) to re-format if needed.

Cleanup ​

ts
// When the section containing the input is removed from the DOM:
section.remove()
tp.destroy()

Released under the MIT License.