# Time Field

> A 24-hour time, typed or picked from a list under the field. "19", "1930", "19.30", and "7pm" all settle as 19:00-style times, and an end time shows how long it makes the event.

- Name: `time-field`
- Status: beta
- Categories: dates, forms
- File: the install writes `time-field.tsx` to your `ui` alias, `@/components/ui` by default.
- Other registry items: `@arbokui/field-frame`, `@arbokui/input`. The install adds them.
- Gallery: https://arbokui.com/components/time-field
- Registry item: https://arbokui.com/r/time-field.json

## Install

1. Add the registry to `components.json`. Do this first, once:

   ```bash
   npx shadcn@latest registry add "@arbokui=https://arbokui.com/r/{name}.json"
   ```

   The command writes this entry. You can also add it by hand:

   ```json
   {
     "registries": {
       "@arbokui": "https://arbokui.com/r/{name}.json"
     }
   }
   ```

   Without this step, the shadcn CLI looks up `@arbokui` in a public list that Arbokui does not control.

2. Add the theme once per app. It replaces your color tokens with ones checked for contrast:

   ```bash
   npx shadcn@latest add @arbokui/theme
   ```

3. Add the component:

   ```bash
   npx shadcn@latest add @arbokui/time-field
   ```

## Use it for

- A start or end time for a meeting, a session, or a booking. Pair it with a DatePicker for a date and a time.
- Give it a label, like "Starts". Without one, pass aria-label.
- The value is "HH:MM" on a 24-hour clock, or "" for none. onValueChange only ever gets a good time.
- Typed text settles when the field is left or Enter is pressed. Text it cannot read says so in red, and the last good time stays.
- For an end time, pass the start as from. The list begins after it, each time says how long that makes it, and the field shows the length.
- step sets the minutes between listed times. Any minute can still be typed. min and max default to 06:00 and 23:00.

## Avoid it for

- A length of time, like 90 minutes. Use a NumberStepper with a duration UnitSwitch.
- A date. Use a DatePicker.
- Times that cross midnight. The value has no date, so 23:30 to 00:30 cannot be told from a backwards range.

## Props

- `label`: `ReactNode`. Names the field, above it.
- `value`: `string`. The time, "HH:MM", or "" for none. Use it with onValueChange.
- `defaultValue`: `string`. Default `""`. The time at first render, when you do not control it.
- `onValueChange`: `(time: string) => void`. Called with a good "HH:MM" once the field settles, or "" when cleared.
- `from`: `string`. The start, for an end time. The list begins after it and says each length.
- `step`: `number`. Default `15`. Minutes between listed times.
- `min`: `string`. Default `"06:00"`. The earliest time allowed.
- `max`: `string`. Default `"23:00"`. The latest time allowed.
- `placeholder`: `string`. Default `"--:--"`. Shown while the field is empty.
- `hint`: `ReactNode`. A short note under the field.
- `error`: `ReactNode`. Replaces the hint, in red. The field's own reading problems show first.
- `size`: `"sm" | "md" | "lg"`. Default `"md"`. Height and text size of the input, the label, and the list.
- `disabled`: `boolean`. Default `false`. Blocks typing and the list.
- `defaultOpen`: `boolean`. Default `false`. Opens the list on first render, for docs and screenshots.
- `name`: `string`. Form field name. Sends the settled time.
- `className`: `string`. Classes for the frame. Later classes win.

## Accessibility

- The input is a combobox. It says it has a list, and whether the list is open.
- Focus stays in the input. The highlighted time is its active descendant, so screen readers read it as the keys move.
- Typing, a click, or the down arrow opens the list at the nearest time. The arrows move a step, and Page Up, Page Down, or Shift with an arrow move an hour.
- Enter takes the highlighted time once the keys have moved it. Otherwise it takes the typed one. Home and End stay in the text.
- The first Esc closes the list, and the next puts back the last good time. With nothing to undo, Esc goes on to the page.
- A problem reading the time is shown in red under the field and announced once. The input is marked invalid.
- For an end time, the length after the time describes the input.

## Examples

### A start and an end

```tsx
const [start, setStart] = useState("19:00");
const [end, setEnd] = useState("20:30");

<TimeField label="Starts" value={start} onValueChange={setStart} />
<TimeField label="Ends" value={end} onValueChange={setEnd} from={start} />
```

### Every 30 minutes, in the evening

```tsx
<TimeField label="Workshop" step={30} min="17:00" max="21:00" />
```
