# Time field

> A text field that reads a typed time, such as "7:30pm" or "19:30"

Status: beta. Added in Components 2.16.0.

A text field that reads a typed time, such as "7:30pm" or "19:30".

## Import

```tsx
import { TimeField } from '@oztix/roadie-components/time-field'
```

## Examples

### Default

Type a time the way you would say it: "7:30pm", "7pm", "19:30" or "noon". A time with no "am" or "pm" reads on a 24-hour clock, so "7:30" is morning. The text is read when the field loses focus or on `Enter`. The value is `'HH:MM'` on a 24-hour clock, such as `'19:30'`, or null. A time has no date and no zone, so pair it with a date where it matters, or use [DatePicker](https://ticketsolutionsptyltd.github.io/roadie/components/date-picker.md) with `granularity='minute'`.

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

render(<Default />)
```

### Variants

`hourCycle` sets how the time reads. `12` reads "7:30pm", the house style for anything a buyer sees, and `24` reads "19:30" for dense staff screens. Either clock can be typed into either field.

```tsx
<TimeField aria-label='12-hour' defaultValue='19:30' />
<TimeField aria-label='24-hour' defaultValue='19:30' hourCycle={24} />
```

### Emphasis

```tsx
<TimeField aria-label='Normal' defaultValue='19:30' />
<TimeField aria-label='Subtle' emphasis='subtle' defaultValue='19:30' />
```

### Sizes

```tsx
<TimeField aria-label='Small' size='sm' defaultValue='19:30' />
<TimeField aria-label='Medium' size='md' defaultValue='19:30' />
<TimeField aria-label='Large' size='lg' defaultValue='19:30' />
```

### States

```tsx
{/* Default */}
<TimeField aria-label='Default' defaultValue='19:30' />
{/* Invalid */}
<TimeField aria-label='Invalid' defaultValue='19:30' invalid />
{/* Read only */}
<TimeField aria-label='Read only' defaultValue='19:30' readOnly />
{/* Disabled */}
<TimeField aria-label='Disabled' defaultValue='19:30' disabled />
```

### Composition

#### With Field

Wrap it in [Field](https://ticketsolutionsptyltd.github.io/roadie/components/field.md) for the label and helper text. It takes `invalid`, `required` and `disabled` from the field, and `Field.ErrorText` says why typed text isn't a time.

```tsx
<Field className='max-w-40'>
  <Field.Label>Doors</Field.Label>
  <TimeField />
  <Field.HelperText>Like 7:30pm</Field.HelperText>
  <Field.ErrorText />
</Field>
```

### With a minute step

`minuteStep` sets how far `ArrowUp` and `ArrowDown` move the time. A typed time off the step shows an error, such as "Choose a time in 15-minute steps". Set times at Wobbly Teacup Room run on the quarter hour.

```tsx
<Field className='max-w-40'>
  <Field.Label>Set time</Field.Label>
  <TimeField minuteStep={15} defaultValue='21:15' />
  <Field.ErrorText />
</Field>
```

## Guidelines

### Keep the time with its date and zone

**Do**

```tsx
<DatePicker granularity='minute' timeZone={venue.timeZone} />
```

When the time belongs to a moment, such as doors on a show night, pick the date and time together in the venue's zone.

**Don’t**

Don't store a time on its own and join it to a date later in the browser's zone. Near midnight and across daylight saving that lands on the wrong moment.

## Accessibility

- It's a text input. `ArrowUp` and `ArrowDown` step the time by `minuteStep`, wrapping at midnight.
- The text is read on blur or `Enter`. While text is being edited, `Enter` commits it instead of submitting the form, and `Escape` puts back the last time.
- Unreadable text sets `aria-invalid`, and inside a `Field` points `aria-describedby` at `Field.ErrorText`.
- On its own the field only marks itself invalid. Put it in a `Field` with `Field.ErrorText` so the reason is shown and read out.

## API reference

### TimeField

A text field that reads a typed time, such as "7:30pm" or "19:30".

```tsx
import { TimeField } from '@oztix/roadie-components/time-field'
```

- `value`: `string | null`. The time, as `'HH:MM'` on a 24-hour clock. Pair with `onValueChange`.
- `defaultValue`: `string | null`. The time to start from when uncontrolled.
- `onValueChange`: `((value: string | null) => void)`. Called when typed text is committed, on blur or Enter, or a step is taken, with `'HH:MM'`, or null when the text is empty or names no time.
- `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'`.
- `hourCycle`: `12 | 24`. Defaults to `12`. `12` reads "7:30pm" and `24` reads "19:30". Either is typed in.
- `minuteStep`: `number`. Defaults to `1`. Minutes per step. The arrow keys step by it, and a typed time off the step shows an error.
- `locale`: `string`. Defaults to `'en-AU'`.

Docs updated 10 Oct 2026.
