# Date field

> A text field that reads a typed date, such as "14 mar" or "next fri", and suggests dates as you type

Status: beta. Added in Components 2.16.0.

A text field that reads a typed date, such as "14 mar" or "next fri", and suggests dates as you type.

## Import

```tsx
import { DateField } from '@oztix/roadie-components/date-field'
```

## Examples

### Default

Type a date the way you would say it: "14 mar", "next fri", "tomorrow", "in 2 weeks" or "1/12", which reads day first. The text is read when the field loses focus or on `Enter`, and the field then shows the date in the house style, such as "Fri 27 Nov 2026". The value is a plain ISO date string, `'2026-11-27'`, or null.

Focus the empty field and a list shows what can be typed, such as Today, Next Fri and End of month, each with its date. As you type, the list offers the dates the text could mean: "fr" offers this Friday and, most days, next week's, and "14" offers the 14th of the next few months. The first one is highlighted once you type, so `Enter` takes it. Choose one to set the date. Words read on the calendar of `timeZone`, and dates that `disabled` refuses are left out.

```tsx
function Default() {
  const [date, setDate] = useState(null)
  return (
    <>
      <DateField aria-label='Show date' value={date} onValueChange={setDate} />
      <p className='text-sm text-subtle'>Value: {date ?? 'none'}</p>
    </>
  )
}

render(<Default />)
```

### Variants

`dateStyle` sets how the date reads when the field isn't being edited, using the [date and time](https://ticketsolutionsptyltd.github.io/roadie/foundations/date-and-time.md) styles. `long` is the default. With another `locale`, the field shows and reads back that locale's month and weekday names, and English types in too. Where a local name matches an English one, the local meaning wins, so in Sesotho "27 Jan" is in June. Where a locale shows the month as a number, type the date as `1/12` or in English. Suggestions name what to type in English, such as Next Fri, and show their dates in the locale.

```tsx
<DateField aria-label='Full' dateStyle='full' defaultValue='2026-11-27' />
<DateField aria-label='Long' dateStyle='long' defaultValue='2026-11-27' />
<DateField aria-label='Medium' dateStyle='medium' defaultValue='2026-11-27' />
```

### Emphasis

`normal` is the sunken field surface that `Input` uses. `subtle` swaps the border for a tinted fill.

```tsx
<DateField aria-label='Normal' defaultValue='2026-11-27' />
<DateField aria-label='Subtle' emphasis='subtle' defaultValue='2026-11-27' />
```

### Sizes

```tsx
<DateField aria-label='Small' size='sm' defaultValue='2026-11-27' />
<DateField aria-label='Medium' size='md' defaultValue='2026-11-27' />
<DateField aria-label='Large' size='lg' defaultValue='2026-11-27' />
```

### States

Text that names no date stays in the field so it can be fixed, the field turns danger, and the value becomes null, so nothing stale is submitted. `Escape` puts back the last date. On its own the field only marks itself invalid; put it in a `Field` with `Field.ErrorText` to say why.

```tsx
{/* Default */}
<DateField aria-label='Default' defaultValue='2026-11-27' />
{/* Invalid */}
<DateField aria-label='Invalid' defaultValue='2026-11-27' invalid />
{/* Read only */}
<DateField aria-label='Read only' defaultValue='2026-11-27' readOnly />
{/* Disabled */}
<DateField aria-label='Disabled' defaultValue='2026-11-27' disabled />
```

### Composition

#### With Field

Wrap it in [Field](https://ticketsolutionsptyltd.github.io/roadie/components/field.md) for the label, helper text and spacing. It takes `invalid`, `required` and `disabled` from the field.

```tsx
<Field required className='max-w-64'>
  <Field.Label showIndicator>Show date</Field.Label>
  <DateField />
  <Field.HelperText>Type a date or a day, like 14 Mar or next Fri</Field.HelperText>
  <Field.ErrorText />
</Field>
```

#### With Field and error

When typed text names no date, `Field.ErrorText` shows why, such as "Enter a date, like 14 Mar or next Fri", even when the `Field` isn't marked invalid. That message wins over the error text's own children until the text is fixed. Try typing "someday".

```tsx
<Field className='max-w-64'>
  <Field.Label>Show date</Field.Label>
  <DateField />
  <Field.ErrorText>Choose a show date</Field.ErrorText>
</Field>
```

### With disabled dates

`disabled` takes the same matchers as [Calendar](https://ticketsolutionsptyltd.github.io/roadie/components/calendar.md). A matched date typed in shows an error, such as "Thu 1 Oct 2026 isn't available". Here Wobbly Teacup Room only books shows from today on.

```tsx
const today = plainDateOf(new Date(), viewerTimeZone())

render(
  <Field className='max-w-64'>
    <Field.Label>Show date</Field.Label>
    <DateField disabled={{ before: today }} />
    <Field.ErrorText />
  </Field>
)
```

### With the venue's today

Words like "today" and "next fri" are read on the calendar of `timeZone`, the viewer's by default. Pass the venue's zone when the date belongs to the venue. Just after midnight in Sydney, as Saturday starts, it's still Friday in Perth.

```tsx
<Field className='max-w-64'>
  <Field.Label>Show date in Perth</Field.Label>
  <DateField timeZone='Australia/Perth' />
</Field>
```

## Guidelines

### Say what can be typed

**Do**

```tsx
<Field.HelperText>
  Type a date or a day, like 14 Mar or next Fri
</Field.HelperText>
```

Give an example in the helper text, so people know they can type words as well as dates.

**Don’t**

```tsx
<DateField placeholder='DD/MM/YYYY' />
```

Don't ask for a fixed format. The field reads many, and a placeholder disappears as soon as someone types.

### Choose the picker when the calendar helps

**Do**

Use DateField alone when people know the date, such as a date of birth or a date on a document.

**Don’t**

Don't make people type a date they would pick by weekday or week. Use [DatePicker](https://ticketsolutionsptyltd.github.io/roadie/components/date-picker.md), which adds a calendar.

## Accessibility

- It's a combobox: a text input with a list of suggestions. `aria-expanded` says when the list is open, and `aria-activedescendant` points at the highlighted suggestion, so screen readers announce it while focus stays in the text.
- Focusing the empty field opens the hints with nothing highlighted, so `Enter` still submits the form. While the list is open, the rest of the page is hidden from screen readers, as with any open combobox; `Escape` or leaving the field closes it. Once you type, the first suggestion is highlighted and `Enter` takes it. The arrow keys move through the list, and `Escape` closes it and keeps the text.
- `Tab` and blur read the typed text itself, not the highlighted suggestion, and `Enter` reads it when no suggestion is highlighted. While text is being edited, `Enter` commits it instead of submitting the form, and `Escape` with the list closed puts back the last date instead of closing a surrounding popover or dialog.
- Unreadable text sets `aria-invalid`. Inside a `Field`, `aria-describedby` points at `Field.ErrorText`, which says what to type and is announced as an alert.
- With a `name`, a hidden input submits the ISO date, so a form never receives the formatted text. A disabled field submits nothing.

## API reference

### DateField

A text field that reads a typed date, such as "14 mar" or "next fri", and suggests dates as you type.

```tsx
import { DateField } from '@oztix/roadie-components/date-field'
```

- `value`: `string | null`. The date, as an ISO date such as `'2026-11-27'`. Pair with `onValueChange`.
- `defaultValue`: `string | null`. The date to start from when uncontrolled.
- `onValueChange`: `((value: string | null) => void)`. Called when typed text is committed, on blur or Enter, with an ISO date, or null when the text is empty or names no date.
- `disabled`: `boolean | CalendarMatchers`. `true` turns the field off. Matchers, as on `Calendar`, refuse those dates: typing one shows an error. Inherits `true` from `Field`.
- `invalid`: `boolean`. Marks the field as invalid. Inherits from `Field` when omitted.
- `size`: `"sm" | "md" | "lg"`. Defaults to `'md'`.
- `emphasis`: `"normal" | "subtle"`. Defaults to `'normal'`.
- `dateStyle`: `"full" | "long" | "medium"`. Defaults to `'long'`. How the date reads when not being edited, from the datetime formatters.
- `today`: `string`. Today as an ISO date, for words like "today" and "next fri".
- `timeZone`: `string`. IANA zone whose calendar decides today. Defaults to the viewer's.
- `weekStart`: `number`. Defaults to `1`. First day of the week, for "next week": 1 is Monday and 7 is Sunday.
- `locale`: `string`. Defaults to `'en-AU'`.

Docs updated 10 Oct 2026.
