Skip to content
WANCRAFT

F.204Forms & Inputs

Clock Picker

An analog time picker: drag the hand round an hour ring, then a minute ring, with snapping, AM / PM and an editable readout.

NewReactTailwindCSSadvanced

Overview

Clock Picker chooses a time on a clock face. Pick the hour first — on a 12-hour dial with an AM / PM toggle, or a 24-hour dial with 13–23 and 00 on an inner ring — then the minute, by tapping or dragging the hand, which snaps to the minute step and always turns the short way round. The digital readout above the dial is editable (type two digits, or use the arrow keys), Hour / Min tabs switch rings, and the dial itself is an ARIA slider: arrows change the value, Page Up / Page Down jump, Home / End go to the ends and Enter moves from hours to minutes. Times are a controlled 24-hour "HH:mm" string, while the display — the formatted time, the AM / PM labels and whether they come first — follows the locale through Intl. Use it inline, or as a field button that opens the face in a native popover and returns focus when it closes.

01Installation

Method 01 · Registry

CLI verified

Uses the shadcn CLI in a project initialised with shadcn init. Installs the file to components/ui/clock-picker.tsx and adds its dependencies.

npx shadcn@latest add https://wancraft.my/r/clock-picker.json

Method 02 · Copy and paste

  1. 1. No extra dependencies — React and Tailwind CSS only.
  2. 2. Copy the source from the Code tab into components/ui/clock-picker.tsx.
  3. 3. Import it and adjust props.
Dependencies
None
Peer
react ≥ 18, tailwindcss ≥ 4
Added
13 Oct 2026
Updated
—

02Usage

The default configuration. Change properties above to generate a tailored example in the Usage tab.

example.tsx
import { ClockPicker } from "@/components/ui/clock-picker";
import { useState } from "react";

export function ClockPickerExample() {
  const [time, setTime] = useState("09:30");

  return (
    <ClockPicker value={time} onChange={setTime} label="Start time" />
  );
}

03Props

PropTypeDefaultDescription
value / defaultValuestring— / "09:30"Controlled time as 24-hour "HH:mm", or the initial time when uncontrolled.
onChange(value: string) => void—Called with the new "HH:mm" whenever the time changes.
hourCycle"auto" | "12" | "24""auto"12-hour dial with AM / PM, 24-hour dial with an inner ring, or the locale's preference.
minuteStepnumber5Minute snapping for the dial and arrow keys; rounded down to a divisor of 60.
variant"inline" | "popover""inline"The face on the page, or a field button that opens it in a native popover.
localestring"en-US"Formatting, AM / PM labels and their position (Intl.DateTimeFormat).
labelstring"Time"Visible label and accessible name.
autoAdvancebooleantrueAfter an hour is picked on the dial (or typed), move on to minutes.
sizenumber232Dial diameter in px.
accentstring"#FF7448"Hand, knob, active readout and focus colour.
disabledbooleanfalseDisables every part of the picker.
namestring—Submits "HH:mm" in a hidden input.

04Features

  • 01Hour ring then minute ring, picked by tap or drag; the hand snaps and always turns the short way
  • 0212-hour dial with an AM / PM toggle, or 24-hour with 00 and 13–23 on an inner ring
  • 03Editable digital readout: type two digits or use Up / Down; Hour / Min tabs switch rings
  • 04Minute step snapping (1, 5, 15…) with tick marks when finer than five minutes
  • 05Intl formatting: the time, localised AM / PM labels and their order (e.g. 午前 before the time)
  • 06Inline or popover variant on the native popover API, with focus returned to the field button
motion · tweeninput · draginput · clickinput · keyboardinput · focus

05Accessibility

  • The dial is role="slider" with aria-valuetext such as "9:30 AM, hour": arrows change the hour or minute, Page Up / Page Down jump 3 hours or 5 minutes (15 with a 5-minute step), Home / End go to the ends and Enter moves from hours to minutes.
  • The readout fields are spinbuttons labelled Hours and Minutes; typing two digits commits, Up / Down step and Page Up / Down jump.
  • Hour / Min are real tabs (aria-selected, Left / Right arrows) controlling the dial's tabpanel; AM / PM are toggle buttons with aria-pressed.
  • The popover is a native popover with role="dialog": the dial is focused on open, Escape closes only the popover, and focus returns to the field button.
  • Numbers and the hand are aria-hidden; the slider's value text carries the meaning. With reduced motion the hand and rings move without transitions.

06Limitations

  • Readout digits are Latin (0–9) in every locale; the formatted time below the dial uses the locale's digits.
  • There is no min / max time or disabled-times option.