Accessibility
DateTimePicker stacks a DatePicker with one or two native <input type="time"> fields (via TimePicker or TimeRangeInputs). The grid ships react-day-picker semantics; the time inputs inherit platform accessibility. The component does not wrap itself in a landmark or announce draft or committed values—the app owns the group name, labels for each time field, and any Apply-time announcement.
react-day-picker roles on the date grid (roving tabindex, arrow-key navigation, aria-selected, aria-disabled).TimePicker renders <input type="time"> with an @prepared911/ui-core Label. TimeRangeInputs renders two of them with an en-dash separator and localized "From" / "To" labels.maxRange is set and the operator pushes the end beyond the cap, the component clamps the value and the field updates in place: assistive tech hears the change.onApply, drafts stay internal and only Apply emits onChange to the parent.role="group" with an aria-label / aria-labelledby when hosted in a popover or form section.TimeRangeInputs ships labels; if you compose TimePicker directly, set label on each.DatePicker.<input type="time">; keyboard handling is platform-defined (arrow keys typically adjust the focused segment: hours, minutes, or AM/PM).role="grid" with role="gridcell" cells from react-day-picker.<input type="time"> with an adjacent Label.<button> via @prepared911/ui-core Button.The picker does not move focus on mount or on Apply. When hosted in a popover, focus the grid (or your preferred entry point) when the popover opens and restore focus to the trigger when it closes.
ids. The underlying time Input uses id for its Label; reusing ids breaks the label association.onApply is present, make the draft-vs-committed distinction obvious in visible copy near the control.Date; the timezone assumption lives in the app.