Skip to content

ComponentsDate & Time

Date Field

Segmented date and time inputs that users type into or step with the arrow keys. DateField and TimeField format every segment for the user's locale, support time zones and any granularity down to seconds, and validate against min/max, required and custom rules.

React AriaSource
Invoice date
mmddyyyy
As printed on the invoice.

Installation

pnpm dlx shadcn@latest add @desyne/date-field

The CLI installs dependencies and any other components this one uses.

Usage

tsx
import { DateField, TimeField } from "@/components/ui/date-field";
import { parseDate, Time } from "@internationalized/date";
tsx
<DateField label="Invoice date" defaultValue={parseDate("2027-01-15")} />
<TimeField label="Standup" defaultValue={new Time(9, 30)} />

Values are @internationalized/date objects

DateField takes a CalendarDate, CalendarDateTime or ZonedDateTime, and TimeField takes a Time (or either date-time type). Create them with parseDate, parseDateTime, parseZonedDateTime, today() or new Time() from @internationalized/date. onChange gives you the same type back, so time zones and calendar systems are never lost in a round trip.

When to use

  • Date Field — dates users already know and type faster than they click: birthdays, document and expiry dates.
  • Time Field — a time of day without a date: opening hours, reminders, recurring schedules.
  • Date Picker — the same field plus a calendar popover, for dates users need to see in context ("next Tuesday").
  • Calendar — an always-visible grid, when there's room and browsing the month matters.

Prefer these over <input type="date">: the segments are consistent across browsers, follow the user's locale and calendar, and are fully accessible.

Anatomy

tsx
<DateField>              {/* or <TimeField> */}
  <Label />              {/* from label */}
  <DateInput>            {/* the field chrome */}
    <DateSegment />      {/* month */}
    <DateSegment />      {/* literal "/" */}
    <DateSegment />      {/* day, year, hour, … */}
  </DateInput>
  <Description />        {/* from description */}
  <FieldError />         {/* from errorMessage / validation */}
  <input type="hidden" /> {/* for form submission */}
</DateField>
PartRendersNotes
DateField<div>Root. Labels, validation and the hidden form input. data-slot="date-field".
TimeField<div>Same structure for times. data-slot="time-field".
DateInput<div role="group">Draws the field chrome with the shared variant and size styles. data-slot="date-input".
Segment<span role="spinbutton">One per editable part. Literals (/, :, spaces) are plain spans with data-type="literal".
Label<span>Rendered when label is set. Adds a red * when isRequired.
Description<span slot="description">Rendered when description is set.
FieldError<span>Shown when the field is invalid. Uses errorMessage, or the browser's message.

DateInput is exported on its own, so you can build a custom layout inside React Aria's DateField or TimeField and still get the library's field styles.

Examples

Controlled

value and onChange own the value. Set it to null to clear every segment. date.toString() gives an ISO 8601 string for storage or APIs.

Contract start
1152027

Starts January 15, 2027 · ISO 2027-01-15

Granularity

granularity sets the smallest segment shown: day (default for dates), hour, minute or second. Time granularities need a value that has a time, such as CalendarDateTime or ZonedDateTime; without a value, the field picks the right type for you.

day
3152027
hour
31520272PM
minute
3152027230PM
second
315202723045PM

Time field

TimeField shows hours, minutes and the day period. Its value is a Time.

Daily standup
930AM
In your local time.

Time options

granularity works on TimeField too (hour, minute by default, or second). hourCycle={24} forces a 24-hour clock regardless of locale.

Hours only
6PM
24-hour
1845
With seconds
64530PM

Time zones

With a ZonedDateTime value the field shows the time zone abbreviation and handles daylight saving transitions correctly. Convert between zones with toTimeZone. hideTimeZone hides the abbreviation when the zone is shown elsewhere.

Launch (New York)
3152027900AMEDT
Same moment in Tokyo
31520271000PMGMT+9
Time only, zone hidden
900AM

Placeholder value

When the field is empty, arrow keys start from today (or midnight). placeholderValue changes that starting point, which saves a lot of key presses for birthdays, and also sets the value type when there's no value.

Date of birth
mmddyyyy
Arrow keys start from 1990.
Next maintenance window
mmddyyyy––––AM
Arrow keys start from 2:00 AM.

Min and max

minValue and maxValue mark out-of-range values as invalid and show a localized error. With the default validationBehavior="native" the error appears after the user changes the value or submits the form; this example uses "aria" so it shows immediately.

Report period end
10102026
Within the last 12 months.Value must be 10/5/2026 or earlier.

Validation

isRequired, minValue / maxValue and a custom validate function run together. Pass a function to errorMessage to tailor the text per failure using validationDetails. With validationBehavior="aria" on the form, errors appear as the user types instead of on submit.

Go-live date
mmddyyyy

Form submission

Set name and the value is submitted as an ISO 8601 string (2027-03-15, 09:30:00), ready to parse on the server with parseDate or parseTime.

Delivery date
mmddyyyy
Arrival window starts
––––AM

Variants

The same outline, filled and underlined variants as every other field.

Outline
mmddyyyy
Filled
mmddyyyy
Underlined
mmddyyyy

Sizes

Small
mmddyyyy
Medium
mmddyyyy
Large
mmddyyyy

Disabled and read-only

isDisabled removes the field from the tab order. isReadOnly keeps it focusable and readable by screen readers, but the value can't change.

Account created
622024
Last login
9282026
Read-only fields stay focusable.

Locales and calendars

Segment order, separators, the day period and digits follow the locale. Wrap fields in I18nProvider to set one explicitly, and add a -u-ca- extension (fa-IR-u-ca-persian) for other calendar systems.

English (US)
352027445PM
English (UK)
050320271645
German
5320271645
Japanese
2027351645
Arabic (Egypt)
٥٣٢٠٢٧٤٤٥م
Persian calendar
۱۴۰۵۱۲۱۴۱۶۴۵

Leading zeros

Whether months, days and hours are zero-padded comes from the locale. shouldForceLeadingZeros always pads them.

Locale default
352027
shouldForceLeadingZeros
03052027

Recipes

Date of birth

placeholderValue starts the year segment in 1990, autoComplete="bday" enables autofill, and validate enforces a minimum age. The computed age is shown in the description.

Verify your age

You must be 18 or older to open an account.

Date of birth
mmddyyyy

Business hours

One row per day with a Switch and a pair of small TimeFields. Each time field is labelled with aria-label, and the closing time is flagged with isInvalid when it isn't after the opening time.

900AM
to
500PM
900AM
to
500PM
900AM
to
500PM
900AM
to
800PM
900AM
to
300PM
Closed
Closed

Event in another time zone

A date, start and end TimeFields and a time zone Select. toCalendarDateTime and toZoned combine them into one instant, shown back in the viewer's own time zone.

Schedule a webinar

Date
10122026
Starts
300PM
Ends
400PM
Time zone

Starts Oct 12, 2026, 7:00 PM in your time zone.

Accessibility

  • The input is a role="group" labelled by label (or aria-label), and each segment is a role="spinbutton" announced with its name ("month", "hour") and current value.
  • Segments are ordered and labelled for the locale, including right-to-left layouts.
  • Typing digits fills a segment and moves to the next one automatically. Typing a letter in the day period segment switches AM/PM.
  • description and the error message are linked with aria-describedby. Invalid fields set aria-invalid.
  • When name is set, a hidden input carries the value for native form submission and validation.
  • Use autoComplete (for example bday) so browsers can autofill.

Keyboard

KeyAction
TabMoves to the next segment, then out of the field
← / →Moves between segments
↑ / ↓Increments / decrements the focused segment (wraps around)
Page Up / Page DownIncrements / decrements by a larger step
Home / EndSets the segment to its minimum / maximum
0–9Types a value; moves on when the segment is complete
Backspace / DeleteClears the last digit, then the segment

Styling

Data attributes

On the DateField / TimeField root (use group-data-*/field: for children):

AttributePresent when
data-invalidValidation failed or isInvalid is set
data-disabledisDisabled is true
data-readonlyisReadOnly is true
data-requiredisRequired is true

On DateInput:

AttributePresent when
data-focus-within / data-focus-visibleA segment has focus / keyboard focus
data-hoveredHovered with a mouse
data-invalid / data-disabledMirrors the field

On each segment:

AttributePresent when
data-typeAlways: month, day, year, hour, minute, second, dayPeriod, era, timeZoneName or literal
data-placeholderThe segment is empty and showing its placeholder
data-focused / data-focus-visibleThe segment has focus / keyboard focus
data-hoveredHovered with a mouse
data-readonlyNot editable (literals, time zone, read-only fields)
data-invalid / data-disabledMirrors the field

Slots

data-slotElement
date-field / time-fieldRoot
date-inputThe segmented input
label, description, field-errorField text

Style helpers

dateSegmentStyles is the class string applied to every segment. DatePicker reuses it, and you can too when composing your own inputs:

tsx
import { dateSegmentStyles } from "@/components/ui/date-field";

<DateSegment segment={segment} className={dateSegmentStyles} />

The chrome comes from the shared fieldVariants in field.tsx, so variant and size match Text Field and Select. className on the root accepts a function of the render props (isInvalid, isDisabled, isReadOnly, isRequired, state).

API Reference

DateField

Prop

Type

Also accepts every prop of React Aria's DateField.

TimeField

Accepts the same field props (label, description, errorMessage, variant, size, validation, form and focus props) with time-specific values:

Prop

Type

Also accepts every prop of React Aria's TimeField.

DateInput

The segmented input used by both fields. Use it inside React Aria's DateField or TimeField for custom layouts.

Prop

Type

  • Date Picker — a date field with a calendar popover, and date ranges.
  • Calendar — an inline month grid.
  • Number Field — the same stepper interaction for numbers.
  • Text Field — shares the field variants and sizes.