DateField
A date, a time or both, typed one segment at a time in the reader's own order — and the value is an ISO string with its UTC reading beside it.
Import
JSX
import DateField from '@box-kite/react/components/dateField';Usage
Due
10
19
2026
value:
2026-10-19JSX
<DateField label="Due" value={value} onValueChange={setValue} />Date, time, or both
type says what it edits, and the value is the string of that kind: 2026-10-19, 14:30:00, or for a date-time the instant it names on the field's zone. A time is a 12- or 24-hour clock the way the locale reads one, and granularity="second" adds the seconds.Opens at
hh
mm
AM
Lap
hh
mm
ss
Meeting
mm
dd
yyyy
hh
mm
AM
JSX
<DateField type="time" label="Opens at" />
<DateField type="time" label="Lap" granularity="second" hourCycle={24} />
<DateField type="datetime" label="Meeting" />UTC or local
A date-time is typed on somebody's wall clock, and
zone says whose: 'local' (the default, the reader's), 'utc', any IANA zone, or 'none' for a wall clock that belongs to nobody — an alarm, a timetable. A zone that is not the reader's is named after the time, so nobody types a New York time thinking it is theirs.Starts (New York)
mm
dd
yyyy
hh
mm
AM
EDT
value:
nullutc:
nulllocal:
nullJSX
<DateField type="datetime" zone="America/New_York" label="Starts (New York)"
onValueChange={(value, { utc, local }) => save(utc)} />onValueChange hands over every reading an app is likely to want beside the string: utc, the reader's local wall clock, the field zone's zoned one, a Date and the epoch — and null for all of them while a segment is empty.The reader's order, with nothing to parse
Free text is ambiguous —
03/04/2026 is two different days depending on who typed it — so the field never parses what was typed. Each part is its own spin button, laid out in the order and with the separators Intl writes for the locale, and the reader types numbers into the parts.en-US
10
19
2026
02
30
PM
ro-MD
19
10
2026
14
30
de-DE
19
10
2026
14
30
ja-JP
2026
10
19
14
30
sv-SE
2026
10
19
14
30
JSX
<DateField label="ro-MD" locale="ro-MD" defaultValue="2026-10-19" />A paste is the one place text is read, because a whole value arrives at once: ISO in any spelling, or a date the way the reader writes one.
Typing it
Digits move on by themselves
4 in a month is April at once; 1 waits for a 0, 1 or 2. A separator key moves on too, the way it would in a text box.The arrows step and wrap
Up and Down step a segment and wrap like a clock; Page Up and Page Down take a bigger step; Home and End go to its ends. An empty segment starts from today.
Read out in the reader's words
Each segment is named by its unit in the reader's language (
Monat, месяц), and a month reads as its name.In a form
name posts the canonical string, so a server reads 2026-10-19 whatever the reader's locale. required is a real input the browser validates, so an empty field stops the form with the browser's own message, and a form reset puts the default back. min, max and isDateUnavailable mark a value outside them aria-invalid without throwing it away.Check-in
mm
dd
yyyy
JSX
<DateField label="Check-in" name="checkIn" required min="2026-10-19" isDateUnavailable={(day) => day.endsWith('-25')} />Styling
The frame is
textbox's, extended: dateField with compact, invalid and disabled variants, and dateField.segment, dateField.literal, dateField.zone and dateField.label inside it.JSX
Box.components({
dateField: {
children: { segment: { styles: { focus: { bgColor: 'emerald-600' } } } },
},
});DateField props
Everything below is this component’s own. All 235 of Box’s style props work on it too, and those are on /box rather than repeated here.
| Prop | Type | Default | What it does |
|---|---|---|---|
type | DateFieldType | 'date' | What it edits: a day ('date', default), a time of day ('time'), or both ('datetime'). |
value | string | null | — | Controlled value, an ISO string of the field's kind: 2026-10-19, 14:30:00, or for a date-time an instant with its offset (2026-10-19T14:30:00+03:00), …Z in UTC, or a wall clock with zone="none". null is empty. Any spelling parse reads is accepted; what comes back is canonical. |
defaultValue | string | null | null | The value it starts with when the field owns its state. |
onValueChange | ChangeHandler<string | null, DateChangeReason, DateChangeDetails> | — | Fires with the new value — null while a segment is empty — and its readings: utc, the reader's local wall clock, a Date, the epoch, and why it changed. |
zone | ZoneInput | 'none' | — | Whose wall clock a date-time is typed on. Default 'local', the reader's; 'utc', any IANA zone or +03:00 for another; 'none' for a wall clock with no zone at all (an alarm, a timetable). A date and a time have no zone, so this only says what "today" is for them. |
locale | string | — | The language the segments are ordered and named in. Default the reader's. |
hourCycle | 12 | 24 | — | A 12- or 24-hour clock. Default the locale's. |
granularity | DateFieldGranularity | 'minute' | Whether a time is edited to the minute (default) or the second. |
min | string | null | — | The earliest value that is valid. A value before it is kept and marked aria-invalid. |
max | string | null | — | The latest value that is valid. |
isDateUnavailable | (date: string) => boolean | — | Days nobody can choose — a weekend, a holiday. Handed the YYYY-MM-DD day. |
disabled | boolean | false | Not editable and not focusable, and read out as such. |
readOnly | boolean | false | Focusable and read out, but not editable. |
required | boolean | false | The form is not valid until it is filled in — the browser's own check, announced and translated for free. |
invalid | boolean | — | Marks the value invalid whatever the bounds say. Default: invalid when out of bounds or unavailable. |
name | string | — | What the value posts under in a form: the canonical string, or nothing while empty. |
label | React.ReactNode | — | The field's visible name, rendered above it. A group of segments is not named by its contents. |
labelledBy | string | — | Names the field after an element already on the page, instead of label. |
describedBy | string | — | An element that describes the field — a hint, an error. |
placeholderValue | string | — | What an empty segment starts from on an arrow key. Default today, at midnight. |
disambiguation | Disambiguation | — | What a wall-clock time a zone skips or repeats means. Default 'compatible'. |
showZone | boolean | — | Whether a date-time names its zone after the time. Default: when the zone is not the reader's own. |
end | React.ReactNode | — | Something inside the field, after the segments — a picker's button. |
autoFocus | boolean | — | Focus the first segment on mount. |
emptyText | string | 'Empty' | What an empty segment is read out as. Default 'Empty'. |
tabIndex | number | 0 | Every segment's tab index. Default 0; -1 keeps the field out of the page's tab order, which a grid cell wants. |
DateField keyboard
| Key | Result |
|---|---|
Tab | Every segment is its own tab stop. |
Left / Right | The previous or next segment, in the reading order. |
Up / Down | One more or one less, wrapping round the segment's range. |
PageUp / PageDown | A bigger step: five years, two months, a week, two hours, fifteen minutes. |
Home / End | The segment's lowest and highest value. |
0-9 | Types into the segment, and moves on once no further digit could fit. |
A / P | AM or PM, in the AM/PM segment. |
Backspace | Takes back the last digit, then empties the segment, then moves to the one before. |
DateField accessibility
Implements the WAI-ARIA APG pattern.
- The field is a
role="group"named bylabel; each segment is arole="spinbutton"named by its unit in the reader's language (Monat,месяц), witharia-valuetextsaying the month by name. - An empty segment still carries
aria-valuenow(its placeholder, which is what an arrow starts from) and reads asemptyText. requiredandnameare a real input the browser validates, so an empty required field stops the form and the message is the browser's own.
Swept with axe on every release, in this state:
DateField. No violations, with contrast and landmark rules left to a human. Screen-reader results are not published yet.DateField style tree
Every part the component draws is a node with a name, so a default can be restyled with
Box.components() instead of a selector — and a variant is a name too.dateFieldextends textboxvariants: compact, invalid, disableddateField.labeldateField.segmentvariants: placeholder, disableddateField.literaldateField.zonedateField.validation