Back to Heroui

NumberInput

apps/docs/content/docs/en/react/migration/(components)/numberinput.mdx

3.2.06.7 KB
Original Source
<Callout type="info"> Refer to the [v3 NumberField documentation](/docs/react/components/numberfield) for complete API reference, styling guide, and advanced examples. This guide only focuses on migrating from HeroUI v2. </Callout>

Structure Changes

In v2, NumberInput was a single component with props:

tsx
import { NumberInput } from "@heroui/react";

export default function App() {
  return <NumberInput label="Amount" defaultValue={1024} />;
}

In v3, NumberField requires compound components:

tsx
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 Propv3 LocationNotes
onValueChangeonChangeRenamed event handler
labelUse Label component
descriptionUse Description component
errorMessageUse FieldError component
variantvariant (on NumberField)Simplified to primary | secondary only
colorRemoved (use Tailwind CSS)
sizeRemoved (use Tailwind CSS)
radiusRemoved (use Tailwind CSS)
startContentPlace content manually in Group
endContentPlace content manually in Group
labelPlacementHandle with layout classes
hideStepperOmit NumberField.IncrementButton and NumberField.DecrementButton
isClearableHandle clear functionality manually
classNamesUse className props on individual components
isWheelDisabledRemoved

Migration Examples

Form Validation

<Tabs items={["v2", "v3"]}> <Tab value="v2"> tsx <NumberInput description="Enter the amount" label="Amount" /> <NumberInput errorMessage="Please enter a valid number" isInvalid label="Amount" /> <NumberInput isRequired label="Quantity" /> </Tab> <Tab value="v3"> tsx import { Description, FieldError, Label } from "@heroui/react"; <NumberField> <Label>Amount</Label> <NumberField.Group> <NumberField.DecrementButton /> <NumberField.Input /> <NumberField.IncrementButton /> </NumberField.Group> <Description>Enter the amount</Description> </NumberField> <NumberField isInvalid> <Label>Amount</Label> <NumberField.Group> <NumberField.DecrementButton /> <NumberField.Input /> <NumberField.IncrementButton /> </NumberField.Group> <FieldError>Please enter a valid number</FieldError> </NumberField> <NumberField isRequired> <Label>Quantity</Label> <NumberField.Group> <NumberField.DecrementButton /> <NumberField.Input /> <NumberField.IncrementButton /> </NumberField.Group> </NumberField> </Tab> </Tabs>

Controlled

<Tabs items={["v2", "v3"]}> <Tab value="v2"> ```tsx import { useState } from "react";

const [value, setValue] = useState();

<NumberInput
  value={value}
  onValueChange={setValue}
/>
```
</Tab> <Tab value="v3"> ```tsx 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>
```
</Tab> </Tabs>

Without Stepper Buttons

<Tabs items={["v2", "v3"]}> <Tab value="v2"> tsx <NumberInput hideStepper label="Amount" /> </Tab> <Tab value="v3"> tsx <NumberField> <Label>Amount</Label> <NumberField.Group> <NumberField.Input /> </NumberField.Group> </NumberField> </Tab> </Tabs>

Number Constraints

<Tabs items={["v2", "v3"]}> <Tab value="v2"> tsx <NumberInput label="Quantity" maxValue={100} minValue={0} /> <NumberInput label="Percentage" step={0.1} /> <NumberInput formatOptions={{style: "currency", currency: "USD"}} label="Price" /> </Tab> <Tab value="v3"> tsx <NumberField maxValue={100} minValue={0}> <Label>Quantity</Label> <NumberField.Group> <NumberField.DecrementButton /> <NumberField.Input /> <NumberField.IncrementButton /> </NumberField.Group> </NumberField> <NumberField step={0.1}> <Label>Percentage</Label> <NumberField.Group> <NumberField.DecrementButton /> <NumberField.Input /> <NumberField.IncrementButton /> </NumberField.Group> </NumberField> <NumberField formatOptions={{style: "currency", currency: "USD"}}> <Label>Price</Label> <NumberField.Group> <NumberField.DecrementButton /> <NumberField.Input /> <NumberField.IncrementButton /> </NumberField.Group> </NumberField> </Tab> </Tabs>

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

  1. Component Renamed: NumberInputNumberField
  2. Component Structure: Must use compound components (NumberField.Group, NumberField.Input, etc.)
  3. Label/Description/Error: Use separate components (Label, Description, FieldError)
  4. Stepper Buttons: Must explicitly include NumberField.IncrementButton and NumberField.DecrementButton
  5. Event Handler: onValueChangeonChange
  6. Variant Simplified: v3 supports only variant="primary" and variant="secondary"; color, size, radius removed — use Tailwind CSS
  7. Content Props Removed: startContent, endContent - place manually
  8. Clear Button Removed: isClearable removed - handle manually
  9. Stepper Control: hideStepper removed - omit buttons instead
  10. Label Placement Removed: labelPlacement removed - handle with layout