NumberInput
Migration guide for NumberInput to NumberField from HeroUI v2 to v3
Refer to the v3 NumberField documentation for complete API reference, styling guide, and advanced examples. This guide only focuses on migrating from HeroUI v2.
Structure Changes
In v2, NumberInput was a single component with props:
import { NumberInput } from "@heroui/react";
export default function App() {
return <NumberInput label="Amount" defaultValue={1024} />;
}In v3, NumberField requires compound components:
import { NumberField, Label } from "@heroui/react";
export default function App() {
return (
<NumberField defaultValue={1024}>
<Label>Amount</Label>
<NumberField.Group>
<NumberField.DecrementButton />
<NumberField.Input />
<NumberField.IncrementButton />
</NumberField.Group>
</NumberField>
);
}Key Changes
1. Component Naming
v2: NumberInput
v3: NumberField
2. Component Structure
v2: Single component with props
v3: Compound components: NumberField.Group, NumberField.Input, NumberField.IncrementButton, NumberField.DecrementButton
3. Prop Changes
| v2 Prop | v3 Location | Notes |
|---|---|---|
onValueChange | onChange | Renamed event handler |
label | — | Use Label component |
description | — | Use Description component |
errorMessage | — | Use FieldError component |
variant | variant (on NumberField) | Simplified to primary | secondary only |
color | — | Removed (use Tailwind CSS) |
size | — | Removed (use Tailwind CSS) |
radius | — | Removed (use Tailwind CSS) |
startContent | — | Place content manually in Group |
endContent | — | Place content manually in Group |
labelPlacement | — | Handle with layout classes |
hideStepper | — | Omit NumberField.IncrementButton and NumberField.DecrementButton |
isClearable | — | Handle clear functionality manually |
classNames | — | Use className props on individual components |
isWheelDisabled | — | Removed |
Migration Examples
Form Validation
{/* With description */}
<NumberInput
description="Enter the amount"
label="Amount"
/>
{/* With error message */}
<NumberInput
errorMessage="Please enter a valid number"
isInvalid
label="Amount"
/>
{/* Required */}
<NumberInput isRequired label="Quantity" />import { Description, FieldError, Label } from "@heroui/react";
{/* With description */}
<NumberField>
<Label>Amount</Label>
<NumberField.Group>
<NumberField.DecrementButton />
<NumberField.Input />
<NumberField.IncrementButton />
</NumberField.Group>
<Description>Enter the amount</Description>
</NumberField>
{/* With error message */}
<NumberField isInvalid>
<Label>Amount</Label>
<NumberField.Group>
<NumberField.DecrementButton />
<NumberField.Input />
<NumberField.IncrementButton />
</NumberField.Group>
<FieldError>Please enter a valid number</FieldError>
</NumberField>
{/* Required */}
<NumberField isRequired>
<Label>Quantity</Label>
<NumberField.Group>
<NumberField.DecrementButton />
<NumberField.Input />
<NumberField.IncrementButton />
</NumberField.Group>
</NumberField>Controlled
import { useState } from "react";
const [value, setValue] = useState();
<NumberInput
value={value}
onValueChange={setValue}
/>import { useState } from "react";
const [value, setValue] = useState<number | undefined>();
<NumberField value={value} onChange={setValue}>
<Label>Amount</Label>
<NumberField.Group>
<NumberField.DecrementButton />
<NumberField.Input />
<NumberField.IncrementButton />
</NumberField.Group>
</NumberField>Without Stepper Buttons
<NumberInput hideStepper label="Amount" /><NumberField>
<Label>Amount</Label>
<NumberField.Group>
<NumberField.Input />
</NumberField.Group>
</NumberField>Number Constraints
{/* Min/Max */}
<NumberInput
label="Quantity"
maxValue={100}
minValue={0}
/>
{/* Step */}
<NumberInput label="Percentage" step={0.1} />
{/* Format options */}
<NumberInput
formatOptions={{style: "currency", currency: "USD"}}
label="Price"
/>{/* Min/Max */}
<NumberField maxValue={100} minValue={0}>
<Label>Quantity</Label>
<NumberField.Group>
<NumberField.DecrementButton />
<NumberField.Input />
<NumberField.IncrementButton />
</NumberField.Group>
</NumberField>
{/* Step */}
<NumberField step={0.1}>
<Label>Percentage</Label>
<NumberField.Group>
<NumberField.DecrementButton />
<NumberField.Input />
<NumberField.IncrementButton />
</NumberField.Group>
</NumberField>
{/* Format options */}
<NumberField formatOptions={{style: "currency", currency: "USD"}}>
<Label>Price</Label>
<NumberField.Group>
<NumberField.DecrementButton />
<NumberField.Input />
<NumberField.IncrementButton />
</NumberField.Group>
</NumberField>Component Anatomy
The v3 NumberField follows this structure:
NumberField (Root)
├── Label (optional)
├── NumberField.Group
│ ├── NumberField.DecrementButton
│ ├── NumberField.Input
│ └── NumberField.IncrementButton
├── Description (optional)
└── FieldError (optional)Summary
- Component Renamed:
NumberInput→NumberField - Component Structure: Must use compound components (
NumberField.Group,NumberField.Input, etc.) - Label/Description/Error: Use separate components (
Label,Description,FieldError) - Stepper Buttons: Must explicitly include
NumberField.IncrementButtonandNumberField.DecrementButton - Event Handler:
onValueChange→onChange - Variant Simplified: v3 supports only
variant="primary"andvariant="secondary";color,size,radiusremoved — use Tailwind CSS - Content Props Removed:
startContent,endContent- place manually - Clear Button Removed:
isClearableremoved - handle manually - Stepper Control:
hideStepperremoved - omit buttons instead - Label Placement Removed:
labelPlacementremoved - handle with layout