TimePicker
Time field with segmented hour/minute editing and an optional wheel popover; built on React Aria TimeField.
Each segment is role="spinbutton" with aria-valuemin/max/now; arrows adjust the focused segment.
Rendered as a segmented control — a clock icon, the hour/minute segments, and
the chevron sit as raised tiles inside a tinted track (the same container the
other inputs use); variant tints the track.
import { TimePicker } from '@arshad-shah/cynosure-react';
import { Time } from '@internationalized/date';
export default function Example() {
return (
<div style={{ width: '240px' }}>
<TimePicker aria-label="Meeting time" defaultValue={new Time(9, 30)} />
</div>
);
}
import { TimePicker } from "@arshad-shah/cynosure-react";import { Time } from "@internationalized/date";
<TimePicker aria-label="Meeting time" defaultValue={new Time(9, 30)} />TimePicker accepts a Time value from @internationalized/date. The trigger opens a popover with a wheel picker for hours and minutes.
Hour cycle
Section titled “Hour cycle”Use hourCycle to switch between 12-hour (12) and 24-hour (24) display.
import { TimePicker } from '@arshad-shah/cynosure-react';
import { Time } from '@internationalized/date';
export default function Example() {
return (
<div style={{ display: 'flex', flexDirection: 'column', gap: '0.75rem', width: '240px' }}>
<TimePicker aria-label="12-hour" hourCycle={12} defaultValue={new Time(14, 30)} />
<TimePicker aria-label="24-hour" hourCycle={24} defaultValue={new Time(14, 30)} />
</div>
);
}
Minute step
Section titled “Minute step”Set minuteStep to constrain the wheel’s minute column (e.g. 5-minute or 15-minute intervals).
import { TimePicker } from '@arshad-shah/cynosure-react';
import { Time } from '@internationalized/date';
export default function Example() {
return (
<div style={{ display: 'flex', flexDirection: 'column', gap: '0.75rem', width: '240px' }}>
<TimePicker aria-label="Every 5 minutes" minuteStep={5} defaultValue={new Time(10, 0)} />
<TimePicker aria-label="Every 15 minutes" minuteStep={15} defaultValue={new Time(10, 0)} />
</div>
);
}
Controlled
Section titled “Controlled”Drive the value from parent state with value and onChange.
import { TimePicker } from '@arshad-shah/cynosure-react';
import { Time } from '@internationalized/date';
import { useState } from 'react';
export default function Example() {
const [value, setValue] = useState<Time | null>(new Time(8, 0));
return (
<div style={{ display: 'flex', flexDirection: 'column', gap: '0.5rem', width: '240px' }}>
<TimePicker
aria-label="Start time"
value={value}
onChange={(t) => setValue(t as Time | null)}
/>
<span style={{ fontSize: '0.875rem', color: 'var(--c-fg-muted)' }}>
Selected: {value ? value.toString() : '(none)'}
</span>
</div>
);
}
States
Section titled “States”import { TimePicker } from '@arshad-shah/cynosure-react';
import { Time } from '@internationalized/date';
export default function Example() {
return (
<div style={{ display: 'flex', flexDirection: 'column', gap: '0.75rem', width: '240px' }}>
<TimePicker aria-label="Default" defaultValue={new Time(9, 0)} />
<TimePicker aria-label="Invalid" defaultValue={new Time(9, 0)} invalid />
<TimePicker aria-label="Read-only" defaultValue={new Time(9, 0)} isReadOnly />
<TimePicker aria-label="Disabled" defaultValue={new Time(9, 0)} isDisabled />
</div>
);
}
Accessibility
Section titled “Accessibility”- Hour and minute segments are individual
spinbuttons witharia-valuemin/aria-valuemax/aria-valuenow. - Arrow Up/Down change the focused segment; Arrow Left/Right move between segments.
- The trigger button carries
aria-label="Open time picker"and opens aDialogwith the wheel. - Provide an
aria-label(or pass alabel) so the whole field is announced as a time picker.
Recipes
Section titled “Recipes”- Pair with
DatePickerfor full date-and-time entry. - Use
hourCycle={24}for backend-facing forms;hourCycle={12}for end-user scheduling. - Set
minuteStep={15}for booking flows to keep slots aligned to common intervals.