TimePicker

A time of day or a range of them, chosen from scrolling columns or typed into the field.

Usage

When to use TimePicker, what each prop is for, and what it leaves to you.

When to use

A time of day, picked from scrolling columns or typed into the field. Use it when the reader could mean any minute of the day.
  • A reminder, an alarm, a publish time, a cut-off: one moment the reader chooses.
  • Opening hours, shifts, quiet hours. These are TimeRangePicker cases.
  • A field where the reader wants to browse what is available, which is where disabledTime helps.
Use something else when
  • The choices are a set of slots. Twelve bookable slots are twelve options, so a Select shows them at a glance and cannot produce 09:07. minuteStep and disabledTime give you a picker that looks open when it is not.
  • The reader already knows the time. Someone logging a call types 1430 faster than a panel opens. Use an Input with a mask, or this picker with format={{ format: "HH:mm", type: "mask" }}, which keeps typing first and the panel as a fallback.
  • The date and the time belong together. Two fields leave "23:30 on which day?" unanswered. Use DatePicker with showTime: one value, one validation.
  • You mean a duration. "45 minutes" is not a time of day, and 00:45 in a picker reads as a quarter to one. Use two number inputs, or a Select of durations.

Format, and 12 or 24 hours

format sets what the field shows, what the reader can type, and which columns the panel has, so decide it first.
  • The default is built from showHour, showMinute and showSecond, so a picker with nothing set reads HH:mm:ss and shows three columns.
  • Drop the seconds first. format="HH:mm" removes the seconds column. Almost nothing people schedule needs seconds.
  • Pass {{ format: "HH:mm", type: "mask" }} to lock the field to that template. The reader steps each part with the arrow keys and cannot type a shape that fails to parse.
  • A function format makes the field read-only. Nothing can parse its output back, so typing is turned off. Use one only for a display-only field.
Set the format, not use12Hours
  • Leaving use12Hours out is not the same as false. A format with a, A, LT, LLL or LTS turns on the AM/PM column by itself, so format="h:mm A" is a 12-hour picker with no flag.
  • Match format to use12Hours. With use12Hours, use a format like h:mm a, or the text in the field will not match the panel.
  • Choose the clock from the reader's locale rather than hardcoding one. The AM/PM column is one more column to scroll for readers who do not use it.

Thinning the columns

A default picker offers 24 hours, 60 minutes and 60 seconds. The step props are the easiest way to make it quicker to use.
  • minuteStep={15} turns the minute column into four cells. It suits anything booked, met or delivered, and removes the wrong values instead of hiding them.
  • minuteStep={5} suits cases where quarters are too coarse. Below 5, the column scrolls again.
  • hourStep is rare, and usually means you wanted a Select, unless your slots are hourly.
  • The steps are typed as integer ranges, so 0 and 24 do not compile. They do not round an existing value: 09:07 from the server still shows, with no cell to land on.
  • showSecond={false} removes a column outright. The three show* flags work together: setting one to true turns the other two off, so set all three or none.

Narrowing with disabledTime

disabledTime blocks single hours, minutes or seconds. The minute callback receives the hour already picked, and the second callback the hour and the minute, so a rule that depends on the earlier column is one function.
  • Use it for rules your data sets: outside opening hours, before the request was created, after the shift ends. Use the step props for plain intervals.
  • hideDisabledOptions removes the grayed cells, which also hides that mornings exist and are unavailable. Keep the grayed cells unless the list gets too long to use.
  • Check the same rule on the server. A value can also arrive by paste, by typing, or from an older tab.
  • Say why beside the field. A grayed 08:00 explains nothing, and one line of help text ("bookings open at 09:00") does.
  • The separate disabledHours, disabledMinutes and disabledSeconds props still work but are deprecated. They cannot see each other's values.

TimeRangePicker

TimeRangePicker is two fields sharing one panel and one commit. Three of its props behave differently from the single picker.
  • Set order={false} for overnight ranges. RangePicker sorts the two values, so a shift from 22:00 to 06:00 becomes 06:00 to 22:00, with no error. Turn order off when a range can cross midnight, and handle the wrap yourself.
  • disabledTime takes different arguments here. It is told which field is asking and the value already picked, which is where "the end must be after the start" goes.
  • There is no Now button. Pass showNow to add one, though "now" is rarely clear for a range.
  • allowEmpty takes a pair, so an open-ended range ("from 09:00, no closing time") needs no placeholder value.
  • id takes { start, end }. One label for the whole control names neither field. See the Accessibility tab.

Confirming, and the Now button

TimePicker waits for OK by default. needConfirm is true, unlike on DatePicker, since an hour without a minute is not a time yet.
  • Keep it on whenever more than one column shows. OK is how the reader says the whole value is done.
  • Set needConfirm={false} only for a field with a single unit, like hours alone.
  • With confirm on, onChange fires on OK, on Enter and on the Tab that leaves the field. onCalendarChange fires on every column click, for a live preview beside the field.
  • changeOnScroll is unreliable on a trackpad. It picks whatever a column comes to rest on, so a reader flicking past 14:00 to reach 17:00 can end up with 14:00. It works well with a mouse wheel.
  • Keep the Now button for logs and timestamps. Hide it for scheduling, where "now" is never the answer.

The field itself

variant, status and size work as on every other input.
  • Pick one variant for the whole form, so a time field does not look more or less editable than the text field beside it.
  • Inside a Form, status comes from validation. Set it by hand only outside a Form, and never as the only signal, since a red border is only a color.
  • Give it a real label, and use the placeholder for the format: "HH:mm" tells the reader what they can type.
  • Set defaultOpenValue. Without it the panel opens on 00:00:00, a long scroll from working hours.
  • Style the panel with classNames.popup. The panel renders in a portal, so a descendant selector on the field cannot reach it. In a scrolling drawer or modal, point getPopupContainer at that container. See the Code tab.
  • Theme it through DatePicker. TimePicker reads DatePicker's component tokens, so set them under components.DatePicker. There is no components.TimePicker.

Time zones

TimePicker has no idea of a time zone. It returns a dayjs value in the browser's zone, with today's date attached.
  • A wall-clock time and an instant are different. "The shop opens at 09:00" stays 09:00 in every zone and across daylight saving. "The export ran at 09:00" is an instant, and it moves.
  • For a wall-clock time, store the string. onChange's second argument is already formatted, so you can save "09:00" and never touch a date. Store the zone beside it only if you need it later.
  • For an instant, convert when the value leaves the form and when it comes back. Sending the picker's value through toISOString() gives a time that is right on your machine and an hour off on someone else's.
  • Show the zone next to the field wherever more than one zone is in play. Readers assume their own.
  • Values are dayjs objects. dayjs comes with antd, but add it to your own package.json before you import it (the timezone plugin too), or the import can fail under pnpm.