Dates & Times
How to work with dates and times in Reka UI.
tip
The inner-workings of our date-related components are heavily inspired by the research and work done by the React Aria team at Adobe.
Reka UI date components use Temporal objects. If your environment does not support Temporal natively yet, install the polyfill:
sh
$ npm add temporal-polyfillDate Objects
Reka UI uses immutable Temporal values to represent date/time state:
Temporal.PlainDate: date-only value, e.g.2024-07-10.Temporal.PlainDateTime: date + time without timezone.Temporal.ZonedDateTime: date + time + timezone.Temporal.PlainTime: time-only value (used inTimeField/TimeRangeField).
These map to exported Reka UI types:
TemporalDate→PlainDate | PlainDateTime | ZonedDateTimeTimeValue→PlainTime
Creating values
ts
import { Temporal } from 'temporal-polyfill'
const date = Temporal.PlainDate.from({ year: 2024, month: 7, day: 10 })
const parsedDate = Temporal.PlainDate.from('2024-07-10')
const dateTime = Temporal.PlainDateTime.from('2024-07-10T12:30:00')
const zoned = Temporal.ZonedDateTime.from('2024-07-12T00:45-04:00[America/New_York]')
const localToday = Temporal.Now.plainDateISO(Temporal.Now.timeZoneId())
const losAngelesToday = Temporal.Now.plainDateISO('America/Los_Angeles')
const time = Temporal.PlainTime.from({ hour: 9, minute: 30 })Updating values (immutability)
Temporal values are immutable. Always reassign when updating.
ts
import { Temporal } from 'temporal-polyfill'
let placeholder = Temporal.PlainDate.from({ year: 2024, month: 7, day: 10 })
placeholder = placeholder.with({ month: 8 })
placeholder = placeholder.add({ months: 1 })
placeholder = placeholder.subtract({ days: 5 })Parsing API/database strings
ts
import { Temporal } from 'temporal-polyfill'
const date = Temporal.PlainDate.from('2024-07-10')
const dateTime = Temporal.PlainDateTime.from('2024-07-10T12:30:00')
const zoned = Temporal.ZonedDateTime.from('2024-07-12T00:45-04:00[America/New_York]')
// UTC/absolute timestamp -> zoned value
const absolute = Temporal.Instant
.from('2024-07-12T07:45:00Z')
.toZonedDateTimeISO('America/New_York')Common gotchas
- Month indexing: months are 1-indexed (
January = 1). - Immutability: methods return new values (
date = date.add(...)). - Timezone-sensitive events: use
Temporal.ZonedDateTime. - Type consistency: keep the same Temporal shape for a given component flow.
reka-ui/date helpers
ts
import type { TemporalDate } from 'reka-ui'
import {
createDateRange,
createDecade,
createMonth,
createYear,
createYearRange,
getDaysInMonth,
getWeekNumber,
hasTime,
isAfter,
isAfterOrSame,
isBefore,
isBeforeOrSame,
isBetween,
isBetweenInclusive,
isCalendarDateTime,
isZonedDateTime,
parseStringToDateValue,
toDate,
} from 'reka-ui/date'
import { Temporal } from 'temporal-polyfill'
const date = Temporal.PlainDate.from({ year: 1995, month: 8, day: 18 })
const minDate = Temporal.PlainDate.from({ year: 1995, month: 8, day: 1 })
const maxDate = Temporal.PlainDate.from({ year: 1995, month: 8, day: 31 })
parseStringToDateValue('1995-08-18', date) // -> TemporalDate
toDate(date) // -> Date
isCalendarDateTime(date) // false
isZonedDateTime(date) // false
hasTime(date) // false
getDaysInMonth(date) // 31
getWeekNumber(date, 'en-US', 'sun')
isAfter(date, minDate)
isBeforeOrSame(date, maxDate)
isAfterOrSame(date, minDate)
isBefore(date, maxDate)
isBetweenInclusive(date, minDate, maxDate)
isBetween(date, minDate, maxDate)
createMonth({ dateObj: date, weekStartsOn: 0, locale: 'en', fixedWeeks: true })
createYear({ dateObj: date, numberOfMonths: 2, pagedNavigation: true })
createDecade({ dateObj: date, startIndex: -10, endIndex: 10 })
createDateRange({ start: date, end: Temporal.PlainDate.from({ year: 2005, month: 8, day: 18 }) })
createYearRange({ start: date, end: Temporal.PlainDate.from({ year: 2005, month: 8, day: 18 }) })
const _: TemporalDate = date