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 Prop | v3 Location | Notes |
|---|---|---|
label | — | Use Label component |
description | — | Use Description component |
errorMessage | — | Use FieldError component |
value, defaultValue, onChange | TimeField | Same (React Aria) |
minValue, maxValue, granularity, placeholderValue | TimeField | Same |
isRequired, isDisabled, isReadOnly, isInvalid, name | TimeField | Same |
validationBehavior, shouldForceLeadingZeros | TimeField | Same |
variant | DateInputGroup | Simplified to primary | secondary only |
fullWidth | TimeField or DateInputGroup | On root or group |
color | — | Removed (use Tailwind CSS) |
size | — | Removed (use Tailwind CSS) |
radius | — | Removed (use Tailwind CSS) |
labelPlacement | — | Handle with layout |
startContent | DateInputGroup.Prefix | Use Prefix child |
endContent | DateInputGroup.Suffix | Use Suffix child |
classNames | — | Use className on TimeField and DateInputGroup parts |
groupProps | — | Use className or DOM props on DateInputGroup |
labelProps | — | Use className on Label |
fieldProps | — | Use className on DateInputGroup |
innerWrapperProps | — | Use className on group/input parts |
descriptionProps | — | Use className on Description |
errorMessageProps | — | Use className on FieldError |
inputRef | — | Ref 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
- Component Renamed:
TimeInput→TimeField - Component Structure: Must use compound components:
TimeField(root) andDateInputGroupwithDateInputGroup.Input(render prop) andDateInputGroup.Segment - Label/Description/Error: Use separate components (
Label,Description,FieldError) - Time Props Unchanged:
value,defaultValue,onChange,minValue,maxValue,granularity,placeholderValue,isRequired,isDisabled,isInvalid,name,validationBehavior,shouldForceLeadingZerosstay onTimeField - Variant on DateInputGroup: v3 supports only
variant="primary"andvariant="secondary"onDateInputGroup;color,size,radiusremoved — use Tailwind CSS - Start/End Content:
startContent/endContent→DateInputGroup.PrefixandDateInputGroup.Suffix - Label Placement Removed:
labelPlacementremoved — handle with layout - DOM/Class Props:
groupProps,labelProps,fieldProps,classNamesremoved — useclassName(and standard DOM props) on the relevant parts