f-ui
Components

Time Input

Segmented React Aria time field with locale-aware hour, minute, and AM/PM slots aligned to shadcn tokens.

Time Input captures a time-of-day with React Aria segments inside the same bordered shell as the date family. It avoids native <input type="time"> so styling stays on your design tokens and the control works consistently across browsers.

Design guide

  • Segmented over native — Prefer this component (or date pickers with withTime) over type="time" in product UI.
  • Locale-first — Hour cycle (12h vs 24h) follows locale unless you set hourCycle.
  • Minute by default — Use granularity="second" only when sub-minute precision matters.
  • Validate on blur — Partial typing is allowed while focused; commit when the user leaves the field.
  • Range + time — Use two Time Inputs (or Date Range Picker withTime) for start and end; never one shared clock for both ends.

Installing

pnpm dlx shadcn@latest add https://ui.isaacfei.com/r/time-input.json

Usage

import { useState } from "react";
import { TimeInput } from "@/components/f-ui/time-input/time-input";

export function Example() {
  const [time, setTime] = useState<Date>();
  return (
    <TimeInput
      label="Start time"
      value={time ?? null}
      onChange={setTime}
    />
  );
}

Embed only the field (no label) via TimeInputControl — used inside calendar range footers:

import { TimeInputControl } from "@/components/f-ui/time-input/time-input";

Examples

930AM

Locale-aware segments; use arrow keys to adjust.

"use client";

import { useState } from "react";

import { TimeInput } from "@/components/f-ui/time-input/time-input";

export function TimeInputDemo() {
  const [time, setTime] = useState<Date | undefined>(
    () => new Date(2026, 4, 21, 9, 30, 0, 0),
  );

  return (
    <div className="max-w-xs w-full">
      <TimeInput
        label="Meeting time"
        value={time ?? null}
        onChange={setTime}
        description="Locale-aware segments; use arrow keys to adjust."
      />
    </div>
  );
}

API Reference

PropTypeDefault
valueDate | null
onChange(time: Date | undefined) => void
granularity"minute" | "second""minute"
hourCycle12 | 24locale
minValue / maxValueDatetime-of-day bounds
disabledbooleanfalse
isInvalidbooleanfalse
labelReactNode
description / errorMessageReactNode
localestringi18n provider
classNames{ root?, input? }

value / onChange use Date for compatibility with date pickers; only the clock portion is read or written (normalized to today in the local timezone).

On this page