Skip to content
WingoUI
ComponentsTemplatesDocsPricingAI agentsBlogChangelog
  1. Home
  2. Blog
  3. Component guides
  4. React Time Picker: Typed Input, 12 or 24 Hours by Locale
Auf Deutsch lesen
  1. Blog
  2. Component guides
  3. React Time Picker: Typed Input, 12 or 24 Hours by Locale
Component guides
Component guides

React Time Picker: Typed Input, 12 or 24 Hours by Locale

SR
Serban Rusu · Founder of Wingo UI
Oct 19, 2026 · 8 min read

On this page

0%
  1. When is input type="time" enough?
  2. What should a React time picker handle?
  3. How do the React time picker options compare?
  4. How does typing a time work?
  5. How do I show 12 or 24 hours by locale?
  6. What happens on a phone?
  7. How do I submit and validate the time?
  8. Is the time picker accessible?
  9. What are the common time input pitfalls in React?
  10. When should I use the Date Time Picker instead?
  11. How do I add it to my project?
  12. FAQ
    1. How do I show a 24-hour time picker in React?
    2. Can I force input type="time" to show 24 hours?
    3. Is there a shadcn time picker?
    4. What value format should a React time picker use?
    5. Is the Wingo UI Time Picker free?

TL;DR

A good React time picker lets people type the time the way they say it ("1430", "2:30pm", "2p"), shows 12 or 24 hours from the locale while the value stays "HH:mm" in 24 hours, and blocks times outside opening hours. On a phone it should open wheels in a bottom sheet instead of the keyboard. The Wingo UI Time Picker does all of this from a value string, a locale and min, max and disabledTimes.

Published Oct 19, 2026

You need a React time picker for a pickup slot, a meeting or a delivery window. The native <input type="time"> is the first thing to try, and it often ends there: you cannot style its popup, a US visitor sees 2:30 PM while your design shows 14:30, and it has no way to grey out a lunch break. Most packages swap it for a row of hour and minute boxes that you fill one at a time. This guide covers what a time field should do instead (accept "1430" or "2p" typed in one go, follow the locale, respect opening hours, open wheels on a phone), the props that matter in the Wingo UI Time Picker, and a full form example.

When is input type="time" enough?

When you do not need to style it, block single slots or control 12 versus 24 hours. The native element is free, accessible and already works with forms. MDN (opens in a new tab) documents its value as always a 24-hour HH:mm (or HH:mm:ss) string, while the display is chosen from the user's locale or by the browser. It supports min, max and step, and a min later than max wraps past midnight.

The trouble starts when the field has to look like the rest of your form or follow business rules. You cannot add a Now button, show that 1 PM is taken, or keep the hour format the same for every visitor. The long-running react-time-picker (opens in a new tab), says in its README to consider the native time input if you do not need legacy browser support or its extra features.

What should a React time picker handle?

Five things, and the native input covers two of them:

  1. Typing in one go. "1430", "14.30", "9", "2:30pm" and "2p" should all mean what they say. Separate hour and minute boxes make people tab or wait for an auto advance.
  2. 12 or 24 hours from the locale. en-US writes 2:30 PM, en-GB writes 14:30. The stored value should not change with the display.
  3. Limits and blocked times. Opening hours, a lunch break, booked slots. Blocked options should look disabled before anyone submits.
  4. A picker for the mouse. Columns of hours and minutes with the current time centered.
  5. A phone layout. Wheels in a bottom sheet, so a tap does not raise a keyboard over half the screen.

How do the React time picker options compare?

A search for "time input react" mostly turns up segmented fields, one box per hour, minute and AM / PM. Facts are from each project's public docs, as of October 2026.

OptionHow you type12 / 24 hoursValueLimits
<input type="time"> (opens in a new tab)Segments, browser UIChosen from the locale or by the browser"HH:mm"min, max, step, wraps past midnight
react-time-picker (opens in a new tab) (MIT)Separate hour, minute and AM / PM inputs, plus a clockformat (Unicode tokens like HH:mm or h:mm a) and localeDate or string ("22:15:00")minTime, maxTime
Mantine TimePicker (opens in a new tab)Separate segments, optional dropdown of columnsformat="12h" adds an AM / PM segment"HH:mm" or "HH:mm:ss"min, max, presets
Dice UI Time Picker (opens in a new tab)Inline segments with auto advance, popover of columnsDetected from the locale, locale overrides it24 hoursminuteStep, hourStep, secondStep
Wingo UI Time Picker (Pro)One text field: "1430", "2:30pm", "2p"locale, or hourCycle="h12" / "h23""HH:mm"min, max, disabledTimes, minuteStep, strictStep

Mantine is the better pick if your app already uses Mantine, and Dice UI if you want a free shadcn time picker and are happy with segments. Segments are a real design choice: they make an invalid time impossible to type. The cost is that a fast typist cannot just write "1430" and press Tab, which is the case the rest of this guide is about.

How does typing a time work?

The field reads the text when you leave it or press Enter. Type 14 and a colon appears, so "1430" reads as 14:30 as you go. "9" becomes 09:00, "930" becomes 09:30, "14h30" and "14.30" work too, and an a, am, p or pm at the end sets the half of the day. Text that does not parse turns the field red while you type and goes back to the last good time on blur. A time outside min and max moves to the nearest limit.

ArrowUp and ArrowDown step the minutes by minuteStep and commit at once, Shift with an arrow steps an hour, and both skip blocked times. Alt + ArrowDown opens the panel with focus on the hours column.

bash
npx wingo-ui@latest add time-picker
tsx
"use client";
import { useState } from "react";
import { TimePicker } from "@/components/ui/time-picker";
// a slot is blocked when it starts inside the 1 to 2 PM break
const lunchBreak = (time: string) => time >= "13:00" && time < "14:00";
export function PickupTime() {
const [time, setTime] = useState("11:30");
return (
<TimePicker
label="Pickup time"
description="The store is open from 9 AM to 6 PM."
value={time}
onValueChange={setTime}
locale="en-US"
min="09:00"
max="18:00"
minuteStep={15}
disabledTimes={lunchBreak}
clearable
showNow
name="pickup_time"
/>
);
}

disabledTimes gets "HH:mm" strings, and because they are zero padded you can compare them as text. Blocked options are disabled in the columns, an hour with nothing left greys out, and a typed blocked time moves to the nearest free slot.

Type 2:30pm or 1430 into the field below and press Tab, then click it to see the columns.

Type 1430 or 2p and press Tab, then click the field for the columns: the 1 PM lunch hour is greyed out, and ArrowUp steps the minutes
$ npx wingo-ui@latest add time-picker
ProTime Picker docs

How do I show 12 or 24 hours by locale?

Pass locale, and hourCycle="auto" (the default) follows it: en-US shows 2:30 PM, en-GB shows 14:30, and midnight in 12 hours reads 12:00 AM. The value is "HH:mm" in 24 hours whatever the display, so a 12-hour field and a 24-hour field share the same state and the same database column. To force the clock, use hourCycle="h23" for 24 hours everywhere, or "h12" for AM and PM. If you searched for "react time picker 24 hours", hourCycle="h23" is the whole answer.

Without a locale prop, the component reads the UIProvider locale, then the nearest LocaleProvider, then the page's lang and the browser language. With none of them set, it renders en-US on the server and during hydration, because Intl would otherwise format with the server's language and the HTML would not match. Set the React time picker locale once at the root so the first paint is already right. UIProvider is a client component, so the root layout can stay a Server Component:

tsx
import { UIProvider } from "@/lib/ui-config";
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en-GB">
<body>
<UIProvider locale="en-GB">{children}</UIProvider>
</body>
</html>
);
}

Here is the same field with locale="en-GB". Type "2:30pm" anyway: it reads as 14:30.

The same field in en-GB: times read 14:30, there is no AM / PM column, and 2:30pm still parses
$ npx wingo-ui@latest add time-picker
ProTime Picker docs

What happens on a phone?

Below 768px the field opens a bottom sheet with wheels that snap like iOS, and the input is read-only with inputMode="none", so no keyboard opens. The wheels tick under the thumb where the browser supports vibration (Chromium browsers on Android; Safari has no Vibration API). Done commits the time, and dragging the sheet away keeps the old one. responsive={false} gives phones the desktop panel instead.

The wheel itself is exported as TimePickerWheel for alarms and short lists. For durations, dates and other columns, the Picker Wheel is the full component, and the React wheel picker guide explains how the native scroll snap and the 3D rows work. This post stays on the typed field.

How do I submit and validate the time?

name renders a hidden input with the "HH:mm" value, so a plain form or a Server Action gets the same string the native time input would send. The visible input has no name. A form reset returns the field to defaultValue, and Enter commits the typed text before the form reads it.

Validate again on the server, since a client limit is a convenience:

tsx
// app/pickup/actions.ts
"use server";
const TIME = /^([01]\d|2[0-3]):[0-5]\d$/;
export async function schedulePickup(formData: FormData) {
const time = String(formData.get("pickup_time") ?? "");
if (!TIME.test(time)) return { error: "Pick a valid time." };
if (time < "09:00" || time > "18:00") return { error: "Pick a time within store hours." };
// save the pickup here
return { ok: true };
}

Show a server error through the error prop: it replaces the description, marks the field invalid and links the message with aria-describedby. withSeconds switches the value to "HH:mm:ss" and adds a seconds column, and strictStep rounds typed minutes to the step on blur (14:37 becomes 14:35 with a 5 minute step).

Is the time picker accessible?

Yes. The text field is a real input linked to its label and description, with a screen reader hint for the format ("Format HH:mm", from labels.format). Each column in the panel and each wheel is a listbox with options. In the columns, ArrowUp and ArrowDown move and pick, PageUp and PageDown jump five, Home and End go to the ends, ArrowLeft and ArrowRight switch columns, Enter confirms and Escape returns focus to the field. Every visible and spoken string lives in labels, so a German or Romanian app translates the picker without forking it. The React form components guide applies the same rules to every field in a form.

What are the common time input pitfalls in React?

Four mistakes show up as soon as real people use the field: reading "2:30" as afternoon, storing formatted text, dropping the day, and overnight windows.

  • "2:30" in a 12-hour field means 2:30 AM. Without a period the parser reads the hour as written. Type "2:30p", or use 24 hours for schedules that are mostly afternoon.
  • Storing a formatted string. Save "14:30", never "2:30 PM". The formatted text changes with the locale; the value does not.
  • A time without a day. "14:30" has no time zone and no date. When the moment matters (a call across time zones, a reminder), use a date and time field instead.
  • Overnight windows. A night shift from 22:00 to 06:00 is min="22:00" and max="06:00": a min later than max wraps past midnight, like the native input.

When should I use the Date Time Picker instead?

Use the Date Time Picker when you need an absolute moment: a booking, a deadline, a reminder. Its value is a Date, and it shows a calendar beside a column of time slots for the chosen day, with an IANA timeZone, presets such as Tomorrow 9:00, and getTimeSlots for per-day availability (taken slots are struck through). name submits value.toISOString().

tsx
"use client";
import { useState } from "react";
import { DateTimePicker } from "@/components/ui/date-time-picker";
export function BookCall() {
const [value, setValue] = useState<Date | null>(null);
return (
<DateTimePicker
label="Call with Liam Walker"
value={value}
onValueChange={setValue}
minuteStep={30}
startTime="09:00"
endTime="17:00"
disablePast
timeZone="America/New_York"
locale="en-US"
name="call_at"
/>
);
}
Pick a day, then a free slot: taken times are struck through, the zone shows in the footer, and on a phone the slots become a row of chips in a sheet
$ npx wingo-ui@latest add date-time-picker
ProDate Time Picker docs

For a start and an end date, the React date range picker guide covers the range calendar.

How do I add it to my project?

Run npx wingo-ui@latest add time-picker. The CLI copies the source into components/ui, adds the Button, Field, Drawer and the date, locale and motion helpers it imports, and installs the npm packages they need, such as @radix-ui/react-popover, motion, lucide-react, vaul for the phone sheet and date-fns for the date helpers. npx wingo-ui@latest add date-time-picker also brings the Calendar and the Select for the time zone. The Time Picker, Date Time Picker and Picker Wheel are Pro components (pricing). More single-component deep dives are in the component guides category.

Components in this post

  • Time Picker

    A React time picker to type a time or pick it from columns, with 12 / 24 hours by locale, minute steps, limits and wheels on phones.

    Pro
  • Date Time Picker

    A React date time picker: a calendar beside a column of free time slots, presets and a time zone label in one field, a sheet on phones.

    Pro
  • Picker Wheel

    A React iOS-style picker wheel whose columns spin with momentum and snap on a 3D cylinder.

    Pro

FAQ

How do I show a 24-hour time picker in React?

Use a locale that writes 24 hours, such as en-GB or de-DE, or force it with an hour cycle option. In the Wingo UI Time Picker, hourCycle="h23" shows 14:30 whatever the locale, and the value is "14:30" either way.

Can I force input type="time" to show 24 hours?

Not reliably. MDN says the display format is chosen from the user's locale or by the browser, and there is no attribute to override it. The value is always 24-hour HH:mm, so only the display changes.

Is there a shadcn time picker?

shadcn/ui itself has no time picker component as of October 2026; its Date Picker docs pair the calendar with a separate time field. Third-party registries fill the gap: Dice UI installs one through the shadcn CLI, and the Wingo UI Time Picker installs as source with npx wingo-ui@latest add time-picker.

What value format should a React time picker use?

Store "HH:mm" in 24 hours, the same string input type="time" submits. It sorts and compares as text, survives a locale change, and is easy to validate on the server.

Is the Wingo UI Time Picker free?

No. The Time Picker, Date Time Picker and Picker Wheel are Pro components. The Field and Drawer they build on are free, and so is the Duration Picker.

  • Time picker
  • Forms
  • Localization
  • Mobile UI
  • React

Share

SR

About the author

Serban Rusu

Founder of Wingo UI

Serban Rusu founded Wingo UI. He builds its component library, CLI and MCP server, and writes about React interfaces for phones and AI coding agents.

More from Serban
Keep reading

Related posts

All posts
Mobile UI in React

React Wheel Picker: iOS Wheels for Times and Dates

Build a React wheel picker on a native snapping scroller: iOS momentum, rows on a 3D cylinder, a sheet on phones, a typed field on desktop, keyboard support.

SRSerban Rusu·Oct 9, 2026·8 min read
Comparisons and alternatives

Best React Component Library for Mobile in 2026: 9 Compared

The best React component library for mobile web apps in 2026: 9 libraries checked at 390px for bottom sheets, touch targets, safe areas and gestures.

SRSerban Rusu·Oct 9, 2026·12 min read
Mobile UI in React

Web Vibration API: Haptic Feedback on Android and iPhone

The Web Vibration API in 2026: navigator.vibrate on Android, the iPhone switch tick that iOS 26.5 limits to real taps, and a React helper that fails quietly.

SRSerban Rusu·Oct 9, 2026·11 min read
Newsletter

Get new posts by email

New guides, tutorials and comparisons from the Wingo UI blog, sent when they are published.

No spam. Unsubscribe at any time.

WingoUI

Animated, configurable, mobile-first React components and blocks. Copy the source, make it yours, and let your coding agent build with it.

Product

  • Components
  • Templates
  • Pricing
  • AI agents
  • Theme generator

Resources

  • Docs
  • Blog
  • Changelog
  • Changelog RSS
  • llms.txt

Legal

  • Terms
  • Privacy
  • Refunds
  • License
  • Imprint

Component categories

  • Buttons & Actions
  • Inputs
  • Forms
  • Navigation
  • Overlays
  • Feedback
  • Data Display
  • Tables & Lists
  • Charts & Stats
  • Layout
  • Media
  • AI Kit
  • Text & Effects
  • Mobile
  • Commerce
  • Marketing Sections
  • Blocks
  • Hooks & Utilities

© 2026 Wingo UI

Wingo UI