Accessibility
AdvancedDateTimeRangePicker nests a date AdvancedDateRangePicker with one or two time inputs. Keyboard and screen reader semantics come from three places—@prepared911/ui-core SegmentedControl, react-day-picker's grid, and native <input type="time">—wired together by the component. The app owns the accessible name for the whole control, focus handoff between mode strip, date grid, and time fields, and any Apply-time announcement.
SegmentedControl with Before / After / Between items; arrow keys move between them, Space / Enter activates.DatePicker grid as AdvancedDateRangePicker (roving tabindex, arrow navigation, aria-selected, aria-disabled).TimePicker for single-bound modes; TimeRangeInputs (two TimePickers with an en-dash separator) for Between. Each TimePicker renders a native <input type="time"> with an associated Label.maxRange-style clamping. When the time range exceeds a configured maximum in TimeRangeInputs, the component clamps the end: the change fires onChange so assistive tech hears the field update.@prepared911/ui-core Buttons when onApply is provided.00:00 / 23:59 padding applies to the committed value automatically.role="group" with an aria-label or aria-labelledby pointing at a visible heading ("Incident created").TimeRangeInputs ships with localized "From" / "To" labels for its internal pickers; if you compose TimePicker directly, set explicit label values so start and end are distinguishable in speech.DatePicker: Up / Down by week, Left / Right by day.<input type="time">; keyboard behavior is platform-defined (arrow keys adjust hours or minutes depending on focus inside the segmented control some browsers render).SegmentedControl (Radix-based).role="grid" + role="gridcell" cells from react-day-picker.<input type="time"> with an adjacent Label; the @prepared911/ui-core Input supplies the name association.<button> via @prepared911/ui-core Button.When hosted in a Popover, the trigger carries the accessible name; the popover's default focus lands in the mode strip. Operators Tab through mode → grid → start time (→ end time) → Apply / Reset. On commit, the hosting surface closes the popover and restores focus to the trigger. When the operator changes mode mid-flight, focus stays on the mode strip and the next Tab moves into the newly configured grid.
SegmentedControl announces each mode as it receives focus; the grid announces the focused day; the native time input announces the current value. None of these announce the full committed constraint on Apply—echo the result visibly:
Be careful with live regions on fast-changing fields—keep them polite, not assertive, and only announce the result after Apply, not during draft edits.
<input type="time"> rendering and keyboard handling vary across browsers and locales; test in the browsers your operators use.Date objects; the timezone assumption lives in your app, not in the picker.