Pro--% off in--d : --h : --m : --s
HeroUI
ReactMigrationComponents

TimeInput

Migration guide for TimeInput to TimeField from HeroUI v2 to v3

Refer to the v3 TimeField documentation for complete API reference, styling guide, and advanced examples. This guide only focuses on migrating from HeroUI v2.

Structure Changes

In v2, TimeInput was a single component with props:

import { TimeInput } from "@heroui/react";

export default function App() {
  return <TimeInput label="Time" name="time" />;
}

In v3, TimeField requires compound components with DateInputGroup and a render prop for segments:

import { TimeField, DateInputGroup, Label } from "@heroui/react";

export default function App() {
  return (
    <TimeField className="w-[256px]" name="time">
      <Label>Time</Label>
      <DateInputGroup>
        <DateInputGroup.Input>
          {(segment) => <DateInputGroup.Segment segment={segment} />}
        </DateInputGroup.Input>
      </DateInputGroup>
    </TimeField>
  );
}

Key Changes

1. Component Naming

v2: TimeInput
v3: TimeField

2. Component Structure

v2: Single component with props
v3: Compound components: TimeField (root) + DateInputGroup with DateInputGroup.Input (render prop) and DateInputGroup.Segment; optionally DateInputGroup.Prefix and DateInputGroup.Suffix

3. Prop Changes

v2 Propv3 LocationNotes
labelUse Label component
descriptionUse Description component
errorMessageUse FieldError component
value, defaultValue, onChangeTimeFieldSame (React Aria)
minValue, maxValue, granularity, placeholderValueTimeFieldSame
isRequired, isDisabled, isReadOnly, isInvalid, nameTimeFieldSame
validationBehavior, shouldForceLeadingZerosTimeFieldSame
variantDateInputGroupSimplified to primary | secondary only
fullWidthTimeField or DateInputGroupOn root or group
colorRemoved (use Tailwind CSS)
sizeRemoved (use Tailwind CSS)
radiusRemoved (use Tailwind CSS)
labelPlacementHandle with layout
startContentDateInputGroup.PrefixUse Prefix child
endContentDateInputGroup.SuffixUse Suffix child
classNamesUse className on TimeField and DateInputGroup parts
groupPropsUse className or DOM props on DateInputGroup
labelPropsUse className on Label
fieldPropsUse className on DateInputGroup
innerWrapperPropsUse className on group/input parts
descriptionPropsUse className on Description
errorMessagePropsUse className on FieldError
inputRefRef handled by TimeField / React Aria

Migration Examples

With Description and Error

<TimeInput
  description="Select start time"
  label="Start time"
  name="startTime"
/>

<TimeInput
  errorMessage="Please enter a valid time"
  isInvalid
  label="Time"
  name="time"
/>
import { Description, FieldError, Label } from "@heroui/react";

<TimeField className="w-[256px]" name="startTime">
  <Label>Start time</Label>
  <DateInputGroup>
    <DateInputGroup.Input>
      {(segment) => <DateInputGroup.Segment segment={segment} />}
    </DateInputGroup.Input>
  </DateInputGroup>
  <Description>Select start time</Description>
</TimeField>

<TimeField className="w-[256px]" isInvalid name="time">
  <Label>Time</Label>
  <DateInputGroup>
    <DateInputGroup.Input>
      {(segment) => <DateInputGroup.Segment segment={segment} />}
    </DateInputGroup.Input>
  </DateInputGroup>
  <FieldError>Please enter a valid time</FieldError>
</TimeField>

Controlled

import { parseTime } from "@internationalized/date";
import { useState } from "react";

const [value, setValue] = useState(null);

<TimeInput
  label="Time"
  name="time"
  value={value}
  onChange={setValue}
/>
import type { TimeValue } from "@internationalized/date";
import { useState } from "react";

const [value, setValue] = useState<TimeValue | null>(null);

<TimeField
  className="w-[256px]"
  name="time"
  value={value}
  onChange={setValue}
>
  <Label>Time</Label>
  <DateInputGroup>
    <DateInputGroup.Input>
      {(segment) => <DateInputGroup.Segment segment={segment} />}
    </DateInputGroup.Input>
  </DateInputGroup>
</TimeField>

Min/Max and Granularity

import { parseTime } from "@internationalized/date";

<TimeInput
  granularity="minute"
  label="Time"
  maxValue={parseTime("18:00")}
  minValue={parseTime("09:00")}
  name="time"
/>
import { parseTime } from "@internationalized/date";

<TimeField
  className="w-[256px]"
  granularity="minute"
  maxValue={parseTime("18:00")}
  minValue={parseTime("09:00")}
  name="time"
>
  <Label>Time</Label>
  <DateInputGroup>
    <DateInputGroup.Input>
      {(segment) => <DateInputGroup.Segment segment={segment} />}
    </DateInputGroup.Input>
  </DateInputGroup>
</TimeField>

Start/End Content

<TimeInput
  endContent={<ClockIcon />}
  label="Time"
  name="time"
  startContent={<ClockIcon />}
/>
<TimeField className="w-[256px]" name="time">
  <Label>Time</Label>
  <DateInputGroup>
    <DateInputGroup.Prefix>
      <ClockIcon />
    </DateInputGroup.Prefix>
    <DateInputGroup.Input>
      {(segment) => <DateInputGroup.Segment segment={segment} />}
    </DateInputGroup.Input>
    <DateInputGroup.Suffix>
      <ClockIcon />
    </DateInputGroup.Suffix>
  </DateInputGroup>
</TimeField>

Component Anatomy

The v3 TimeField follows this structure:

TimeField (Root)
  ├── Label (optional)
  ├── DateInputGroup
  │   ├── DateInputGroup.Prefix (optional)
  │   ├── DateInputGroup.Input → (segment) => DateInputGroup.Segment
  │   └── DateInputGroup.Suffix (optional)
  ├── Description (optional)
  └── FieldError (optional)

Summary

  1. Component Renamed: TimeInputTimeField
  2. Component Structure: Must use compound components: TimeField (root) and DateInputGroup with DateInputGroup.Input (render prop) and DateInputGroup.Segment
  3. Label/Description/Error: Use separate components (Label, Description, FieldError)
  4. Time Props Unchanged: value, defaultValue, onChange, minValue, maxValue, granularity, placeholderValue, isRequired, isDisabled, isInvalid, name, validationBehavior, shouldForceLeadingZeros stay on TimeField
  5. Variant on DateInputGroup: v3 supports only variant="primary" and variant="secondary" on DateInputGroup; color, size, radius removed — use Tailwind CSS
  6. Start/End Content: startContent/endContentDateInputGroup.Prefix and DateInputGroup.Suffix
  7. Label Placement Removed: labelPlacement removed — handle with layout
  8. DOM/Class Props: groupProps, labelProps, fieldProps, classNames removed — use className (and standard DOM props) on the relevant parts

On this page