Date Range Field

Segmented date range input.

Usage

value is { start, end }, and you render two Inputs — one type="start" and one type="end". type is required; there is no single input that holds a range.

Put the visual separator between them yourself and mark it aria-hidden — a dash read aloud between two dates adds nothing.

Stay dates

You must name the Root

Bits gives the range Root role="group" with no accessible name. Without your help the field announces as an anonymous group.

Verified in the rendered DOM: Bits points each Input's aria-labelledby at your Label, but the Inputs carry no role — so nothing exposed to assistive technology ends up labelled. On the single-value Date Field the Input is the group and Bits does label it, so this gap is specific to ranges.

Pass aria-labelledby pointing at your Label's id, or aria-label. Both reach the root element, and both directions are asserted in the tests so this cannot regress quietly.

Shared with Date Field

Segment is the same component Date Field uses — Bits re-exports the identical module to both namespaces, so one styled implementation serves each and the two cannot drift apart. Everything in that page's "why not a native input" section applies here too.

Props

DateRangeField.Rootvalue and placeholder are bindable.

PropTypeDefault
value The date value range. Bindable. A `DateValue`, not a JS `Date`.{ start: DateValue | undefined; end: DateValue | undefined }
onValueChange Called when the value changes.(value: FieldValue) => void
placeholder Which date the empty segments are formatted from. Bindable.DateValue
minValue Earliest accepted value.DateValue
maxValue Latest accepted value.DateValue
granularity Smallest unit the user can edit, which decides which segments appear. `day` gives a plain date; `minute` adds time segments.'day' | 'hour' | 'minute' | 'second''day'
locale BCP-47 locale. It decides the SEGMENT ORDER — month/day/year versus day/month/year — so getting it wrong does not just relabel the field, it rearranges it. Pass the user's locale.string'en'
name Name for form submission; Bits renders a hidden input.string
required booleanfalse
disabled booleanfalse
readonly booleanfalse
validate Return a message to mark the value invalid. Bits then sets `data-invalid` and wires `aria-invalid` on the segments.(value: never) => string | string[] | void
class Extra classes merged onto the root.string
children Snippet

Input takes a required type of "start" or "end". Label and Segment take class plus their native attributes.