Rxova
Skip to content

Time input

A segmented time field with no clock popup, no date library, and no timezone bugs. Headless, zero-dependency, 12/24-hour from Intl.

A time is three short numbers. Typing 14:30 is faster than opening a dropdown and scrolling a column of sixty minutes — and on a phone the column picker is worse still. Yet every mainstream option ships one, and most cannot turn it off.

ShapeWhat it costs
Dropdown columns of hours/minsA popup, a scroll container, and a lot of DOM
Segmented field plus a clockThe segments you want, and a clock popup you usually don’t
Date and time togetherA calendar you are not using, plus a date library underneath
This packageSegmented field, no popup, 3.8 kB brotli, no dependencies

Sizes are measured: bundled with esbuild, minified, React external, brotli at quality 11.

They bring dependencies for data the platform has. Intl already knows whether a locale is 12- or 24-hour, where the day period sits, and what the AM/PM words are in every language the runtime supports:

import { usesHour12, dayPeriodNames } from '@rxova/react-time-input'
usesHour12('en-US') // true
usesHour12('de-DE') // false
dayPeriodNames('ja-JP') // ['午前', '午後']

They model a time of day as an instant. Date and moment objects across the API boundary are the source of the classic off-by-one-day and off-by-one-hour bugs:

new Date('14:30') // Invalid Date
new Date('2026-01-01T14:30') // a moment that moves with the timezone and with DST

“Half past two” does not move. So this package never constructs one — the value is an HH:mm string end to end.

12-hour handling is where they break. Midnight is 12 AM and hour 0; noon is 12 PM and hour 12. That fold is wrong in exactly two cases out of twenty-four, which is why a sampled test usually misses it and why “my 12:30 booking saved as 00:30” is a perennial bug report. The adversarial suite here sweeps all 24 hours rather than spot-checking.

Terminal window
npm install @rxova/react-time-input
import { useState } from 'react'
import { TimeInput } from '@rxova/react-time-input'
function Booking() {
const [value, setValue] = useState<string | null>(null)
return <TimeInput label="Start time" value={value} onChange={setValue} min="09:00" max="17:00" />
}

3.8 kB brotli, zero runtime dependencies, no stylesheet to import.