# TimeInput

- Page: https://jiguang132.com/resources/astryx/docs/time-input
- Resource: Astryx (https://jiguang132.com/resources/astryx.md)
- All guides: https://jiguang132.com/resources/astryx/docs.md

TimeInput uses a browser/OS time picker on coarse pointers by default and Astryx's typed field on fine pointers. It converts values to a standard format and supports arrow-key adjustment on the typed surface. Use it in forms, scheduling flows, or any interface where users need to select a specific time.

## Installation

```bash
npm install @astryxdesign/core@0.7.1 @astryxdesign/theme-neutral@0.7.1 @stylexjs/stylex@0.19.0
```

Requires React 19+, base CSS and a Theme provider. See [Setup](/resources/astryx/docs/getting-started).

## Time Input

TimeInput uses a browser/OS time picker on coarse pointers by default and Astryx's typed field on fine pointers. It converts values to a standard format and supports arrow-key adjustment on the typed surface. Use it in forms, scheduling flows, or any interface where users need to select a specific time.

| Prop | Type | Default | Description |
|---|---|---|---|
| label * | string |  | Label text for the input (required for accessibility). |
| isLabelHidden | boolean | false | Visually hides the label while keeping it accessible to screen readers. |
| description | string |  | Description text displayed between the label and input. |
| isOptional | boolean | false | Shows an "(optional)" indicator next to the label. Mutually exclusive with isRequired. |
| isRequired | boolean | false | Marks the field as required and sets aria-required. Mutually exclusive with isOptional. |
| isDisabled | boolean | false | Disables the input and suppresses interactions. |
| disabledMessage | string |  | Explains why the input is disabled. With isDisabled, shows a tooltip on hover/keyboard focus and keeps the field focusable via aria-disabled (activation stays blocked). Use this instead of wrapping a disabled TimeInput in Tooltip. Disabled controls swallow the hover events an external Tooltip needs. |
| value | ISOTimeString |  | Controlled time value in ISO format (HH:MM or HH:MM:SS). |
| onChange | (value: ISOTimeString \| undefined) => void |  | Callback fired when the time changes. Receives undefined when the input is cleared. |
| changeAction | (value: ISOTimeString \| undefined) => void \| Promise<void> |  | Async action fired after onChange. Wrapped in a React transition to provide optimistic UI; triggers the loading spinner while pending. |
| isLoading | boolean | false | Puts the input into a loading state, displaying a spinner. |
| min | ISOTimeString |  | Minimum selectable time in ISO format. Values outside the range are rejected. |
| max | ISOTimeString |  | Maximum selectable time in ISO format. Values outside the range are rejected. |
| hasSeconds | boolean | false | Includes seconds in the time display and parsing. |
| hasClear | boolean | false | Shows a clear button when a value is set and the input is not disabled. |
| hourFormat | '12h' \| '24h' | '12h' | Controls the display format. '12h' shows AM/PM (e.g. '2:30 PM'); '24h' uses 24-hour notation (e.g. '14:30'). |
| increment | number | 1 | Number of minutes to add or subtract when the user presses the up or down arrow key. |
| presentation | 'text-input' \| 'popover' \| 'bottom-sheet' \| 'native' \| 'adaptive-bottom-sheet' \| 'adaptive-native' | 'adaptive-native' | Which surface selects the time. 'adaptive-native' (the default) uses Astryx's typed field on a fine pointer and the browser/OS input type=time on a coarse pointer — except hasSeconds or increment other than 1, which retain the typed field because iOS has no seconds wheel and treats step as validation rather than picker cadence; 'native' always uses the browser/OS control with no Astryx fallback; 'adaptive-bottom-sheet' uses the typed field on a fine pointer and Astryx's bottom-sheet time wheels on a coarse pointer; 'bottom-sheet' forces the wheels on every pointer; 'text-input' (like 'popover', which has no distinct TimeInput surface) keeps only the typed field. Native mode forwards min/max and enforces them on commit. hourFormat formats the closed value; the open OS picker follows the device locale. |
| nativePicker | 'touch' \| 'always' \| 'never' | 'touch' | Deprecated: use presentation ('touch' = 'adaptive-native', 'always' = 'native', 'never' = 'text-input'). Still works exactly as released; presentation wins when both are set. |
| placeholder | string | 'Select a time' | Placeholder text shown when no time is selected. When the input is focused and empty, a format hint overrides this text. |
| size | 'sm' \| 'md' \| 'lg' | 'md' | Controls the height of the input element. |
| status | {type: 'warning' \| 'error' \| 'success', message?: string} |  | Status indicator that colors the border and displays an icon. When a message is provided it is rendered below the input. |
| statusVariant | 'attached' \| 'detached' \| 'tooltip' | 'attached' | How the status message is placed relative to the input. attached overlaps directly below the input (bordered treatment); detached floats below as a separate element with spacing; tooltip hides the message box and surfaces it in a tooltip on the status icon. |
| labelTooltip | string |  | Tooltip text rendered as an info icon at the end of the label row. |
| width | SizeValue |  | Width of the field (number = pixels, string used as-is, e.g. "100%"). Sizes the whole field (label, control, and status) so they stay aligned. |
| containerXstyle | StyleXStyles |  | StyleX styles for the Field box around the label, control, and status. containerClassName and containerStyle take a class name and inline styles for the same box. No effect (development warning) where no Field box renders: inside InputGroup (style the group) and in a horizontal-labels FormLayout. |
| controlXstyle | StyleXStyles |  | StyleX styles for the visual control box: the bordered element that holds the text, icons, and end controls, never the native input. controlClassName and controlStyle take a class name and inline styles for the same box. Replaces root xstyle, className, and style, which this component does not accept. |

### Usage guidance

- Base props such as ref, id, data-*, aria-*, and DOM event handlers go to the time input, the element that is focused and announced. A DOM handler runs after TimeInput's own handler for the same event and still receives events it handled (including ones it called preventDefault on), so it cannot cancel built-in behavior.
- Choose the hour format (12h or 24h) that matches your audience's locale: 12-hour with AM/PM for US-centric UIs, 24-hour for international or technical contexts.
- Set min and max constraints when the context has a valid range, like business hours or event windows, so users cannot submit an out-of-bounds time.
- Provide a description or placeholder that hints at the expected format or purpose, like "Business hours: 9 AM – 5 PM".
- Use the status prop to surface validation errors inline: show a message like "Time must be during business hours" so users know exactly what to fix.
- Enable hasClear when the field is optional, so users can remove a previously selected time.
- Place TimeInput inside InputGroup when the time needs a single-line prefix or suffix addon, like a start/end label or timezone marker.
- Avoid: Don't use TimeInput for combined date-and-time selection; pair it with a separate DateInput instead.
- Avoid: Don't hide the label; even when space is tight, keep the label visible or provide a description so the purpose is clear.
- Avoid: Wrap a disabled TimeInput in Tooltip to explain why it is disabled; disabled triggers swallow the hover events the wrapper needs. Use the disabledMessage prop instead.

### Theming API

```json
{
  "targets": [
    {
      "className": "astryx-time-input",
      "visualProps": [
        "size",
        "status"
      ],
      "states": [
        "disabled"
      ]
    }
  ]
}
```

### Anatomy

- **Clock icon**: A leading clock icon that identifies the field and opens the browser/OS picker in native mode.
- **Time control**: A real input type=time in native modes, or Astryx's editable text field for fine pointers, presentation="text-input", seconds, and custom increments.
- **Clear button**: A trailing button to reset the value, shown when hasClear is true and a value is set.
- **Status icon**: A trailing icon indicating error, warning, or success state.
- **Spinner**: Replaces trailing content during loading to show an async action is in progress.


## Examples

- Time Input: A time input that uses the browser/OS picker on touch by default and Astryx typed entry on fine pointers.
- TimeInput — Constrained: Time inputs with min/max constraints limiting selection to specific windows. Use to prevent out-of-bounds selections for appointments, reservations, or shift scheduling.
- TimeInput — Formats: 12-hour, 24-hour, and seconds formats side by side. Use 12h for US-centric UIs, 24h for international or technical contexts, and seconds for precise timing.
- TimeInput — Increment: Time input with a custom step increment. Arrow keys jump by the specified interval (e.g. 15 minutes) for quick slot-based scheduling.
- TimeInput — States: Default, disabled, error, warning, and success states. Use status messages to give users clear feedback about their time selection.

---

Index of all JGuang resources: https://jiguang132.com/llms.txt
