Time Range Picker
A composable, accessible TimeRangePicker component for modern React applications.
tsx
import { TimeRangePicker } from '@nofinite/nui';Interactive Preview
Loading preview...
A popover-based time range selector supporting 12/24-hour clocks, minute stepping, controlled/uncontrolled mode, scrollable hour/minute/AM-PM columns, and start/end part switching. Ideal for booking forms, scheduling interfaces, and time window selection in dashboards.
Usage
Basic usage
tsx
import { TimeRangePicker } from '@nofinite/nui';
<TimeRangePicker />;Controlled usage
tsx
const [range, setRange] = useState({ from: '09:00', to: '17:00' });
<TimeRangePicker value={range} onChange={setRange} />;24-hour clock
tsx
<TimeRangePicker clockType={24} />Minute stepping
tsx
<TimeRangePicker minuteStep={15} />Form integration
tsx
<TimeRangePicker nameFrom="startTime" nameTo="endTime" />Disabled state
tsx
<TimeRangePicker disabled />Variants
Clock variants
tsx
<TimeRangePicker clockType={12} />
<TimeRangePicker clockType={24} />Minute precision variants
tsx
<TimeRangePicker minuteStep={5} />
<TimeRangePicker minuteStep={30} />Control mode variants
tsx
<TimeRangePicker defaultValue={{ from: "09:00", to: "17:00" }} />
<TimeRangePicker value={{ from: "10:30", to: "18:00" }} />Available variants
- 12-hour range picker
- 24-hour range picker
- Stepped minute range picker
- Full precision minute range picker
- Controlled/uncontrolled range picker
- Disabled range picker
- Form-integrated range picker
- Start/End toggle UI
Guidelines
- Default
minuteStep ≥ 5for faster selection - Use 24-hour clock for international or enterprise apps
- Use 12-hour clock for consumer-friendly booking UX
- Always show placeholder until user selects both times
- Ensure popover width fits both
from → tolabels
States
- Closed trigger
- Open popover
- Active part (Start/End)
- Selected hour/minute/AM-PM
- Hover item
- Disabled
- Placeholder
- Focus-visible trigger
Keyboard Interaction
- Trigger opens popover via Enter / Space
- Tab navigates start/end buttons and scroll columns
- Arrow navigation scrolls hour/minute/AM-PM items
- Escape closes popover
- Focus restores to trigger on close
- Footer buttons are accessible via Tab/Enter
Accessibility
- Trigger uses
aria-haspopup="dialog" aria-expandedreflects popover state- Hidden inputs enable form submission
- Focus restoration ensures keyboard continuity
- Selected items are visually highlighted
- Start/End part toggle is keyboard accessible
- Placeholder indicates empty range
z-dropdown | Popover layering |
Best Practices
Do
- Use stepped minutes for faster selection
- Switch
activePartfor proper Start/End selection - Maintain focus restoration
- Use hidden inputs for form integration
- Use 24h clock in global apps
- Combine with date picker for scheduling workflows
Don’t
- Allow very small minuteStep values that break UX
- Disable collision positioning
- Use extremely narrow triggers with long
from → tolabels - Hide popover without focus restoration
- Mix uncontrolled and controlled values inconsistently
API Reference
| Prop | Type | Default | Description |
|---|---|---|---|
value | TimeRange | — | Controlled time range object |
defaultValue | TimeRange | — | Uncontrolled default time range object |
onChange | ((v: TimeRange) => void) | — | Callback fired when either the start or end time changes |
clockType | enum | 12 | Uses 12-hour or 24-hour clock formatting. Defaults to 12. |
minuteStep | number | 1 | Step interval for the minute column. Defaults to 1. |
placeholder | string | Select time range | Placeholder text displayed when no range is selected |
nameFrom | string | — | Name attribute applied to the "from" hidden input for native forms |
nameTo | string | — | Name attribute applied to the "to" hidden input for native forms |
disabled | boolean | false | Disables the picker entirely |