NumberField

A numeric input with increment and decrement buttons for precise value entry.

Import

import { NumberField } from 'heroui-native-pro';

Anatomy

<NumberField>
  <Label>...</Label>
  <NumberField.Group>
    <NumberField.DecrementButton />
    <NumberField.Input />
    <NumberField.IncrementButton />
  </NumberField.Group>
  <Description>...</Description>
</NumberField>
  • NumberField: Root container that manages numeric state, provides form field context (for Label, Description, FieldError), and cascades animation settings to children. Supports controlled and uncontrolled modes with min/max/step constraints and Intl number formatting.
  • NumberField.Group: Plain View wrapper that contains the decrement button, input, and increment button. Accepts a render function for accessing group state.
  • NumberField.Input: Pass-through to the Input component. Displays the formatted numeric value and automatically adds horizontal padding to avoid overlapping with the buttons. Commits the value on blur.
  • NumberField.DecrementButton: Absolutely positioned button anchored to the left side of the input. Decrements the value by one step. Auto-disabled when the value reaches minValue. Supports long-press repeat.
  • NumberField.IncrementButton: Absolutely positioned button anchored to the right side of the input. Increments the value by one step. Auto-disabled when the value reaches maxValue. Supports long-press repeat.

Usage

Basic Usage

The NumberField component uses compound parts to create a numeric input with number stepper buttons.

<NumberField defaultValue={1024} minValue={0}>
  <Label>Width</Label>
  <NumberField.Group>
    <NumberField.DecrementButton />
    <NumberField.Input />
    <NumberField.IncrementButton />
  </NumberField.Group>
</NumberField>

With Description

Add context below the input with a Description component.

<NumberField defaultValue={1024} minValue={0}>
  <Label>Width</Label>
  <NumberField.Group>
    <NumberField.DecrementButton />
    <NumberField.Input />
    <NumberField.IncrementButton />
  </NumberField.Group>
  <Description>Enter the width in pixels</Description>
</NumberField>

Controlled Value

Use value and onChange to control the numeric state externally.

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

<NumberField minValue={0} value={value} onChange={setValue}>
  <Label>Width</Label>
  <NumberField.Group>
    <NumberField.DecrementButton />
    <NumberField.Input />
    <NumberField.IncrementButton />
  </NumberField.Group>
</NumberField>

Step Values

Configure the step size for increment and decrement operations.

<NumberField defaultValue={0} minValue={0} maxValue={100} step={10}>
  <Label>Quantity</Label>
  <NumberField.Group>
    <NumberField.DecrementButton />
    <NumberField.Input />
    <NumberField.IncrementButton />
  </NumberField.Group>
</NumberField>

Format Options

Use Intl.NumberFormatOptions to format the displayed value as currency, percent, unit, or decimal.

<NumberField
  defaultValue={99.99}
  minValue={0}
  formatOptions={{ style: "currency", currency: "USD" }}
>
  <Label>Price</Label>
  <NumberField.Group>
    <NumberField.DecrementButton />
    <NumberField.Input />
    <NumberField.IncrementButton />
  </NumberField.Group>
</NumberField>

Percentage Format

Format the value as a percentage where 0.5 displays as 50%.

<NumberField
  defaultValue={0.5}
  minValue={0}
  maxValue={1}
  step={0.01}
  formatOptions={{ style: "percent" }}
>
  <Label>Percentage</Label>
  <NumberField.Group>
    <NumberField.DecrementButton />
    <NumberField.Input />
    <NumberField.IncrementButton />
  </NumberField.Group>
</NumberField>

Disabled State

Disable the entire number field and its children.

<NumberField isDisabled defaultValue={1024} minValue={0}>
  <Label>Width</Label>
  <NumberField.Group>
    <NumberField.DecrementButton />
    <NumberField.Input />
    <NumberField.IncrementButton />
  </NumberField.Group>
</NumberField>

Invalid State with FieldError

Combine isInvalid with FieldError to display validation messages.

<NumberField isRequired isInvalid={value > 100} minValue={0} value={value} onChange={setValue}>
  <Label>Quantity</Label>
  <NumberField.Group>
    <NumberField.DecrementButton />
    <NumberField.Input />
    <NumberField.IncrementButton />
  </NumberField.Group>
  <Description hideOnInvalid>Enter a value between 0 and 100</Description>
  <FieldError>Quantity must be 100 or less</FieldError>
</NumberField>

Render Function Group

Use a render function on NumberField.Group to access group state.

<NumberField defaultValue={50} minValue={0} maxValue={100}>
  <Label>Value</Label>
  <NumberField.Group>
    {({ canDecrement, canIncrement }) => (
      <>
        {canDecrement && <NumberField.DecrementButton />}
        <NumberField.Input />
        {canIncrement && <NumberField.IncrementButton />}
      </>
    )}
  </NumberField.Group>
</NumberField>

Example

import { Description, FieldError, Label, NumberField, Surface } from 'heroui-native-pro';
import { useState } from 'react';
import { View } from 'react-native';

export default function NumberFieldExample() {
  const [value, setValue] = useState(150);
  const isInvalid = value > 100;

  return (
    <View className="flex-1 justify-center px-5">
      <Surface className="rounded-3xl p-6 gap-6">
        <NumberField defaultValue={1024} minValue={0}>
          <Label>Width</Label>
          <NumberField.Group>
            <NumberField.DecrementButton />
            <NumberField.Input />
            <NumberField.IncrementButton />
          </NumberField.Group>
          <Description>Enter the width in pixels</Description>
        </NumberField>

        <NumberField
          isRequired
          isInvalid={isInvalid}
          minValue={0}
          value={value}
          onChange={setValue}
        >
          <Label>Quantity</Label>
          <NumberField.Group>
            <NumberField.DecrementButton />
            <NumberField.Input />
            <NumberField.IncrementButton />
          </NumberField.Group>
          <Description hideOnInvalid>Enter a value between 0 and 100</Description>
          <FieldError>Quantity must be 100 or less</FieldError>
        </NumberField>
      </Surface>
    </View>
  );
}

API Reference

NumberField

proptypedefaultdescription
childrenReact.ReactNode-Children elements (Label, NumberField.Group, Description, FieldError)
valuenumber-Controlled numeric value
defaultValuenumber-Default value for uncontrolled usage
minValuenumber-Minimum allowed value; disables decrement button at limit
maxValuenumber-Maximum allowed value; disables increment button at limit
stepnumber1Step value for increment and decrement operations
formatOptionsIntl.NumberFormatOptions-Intl.NumberFormat options for formatting (currency, percent, unit, etc)
isDisabledbooleanfalseWhether the entire number field and its children are disabled
isInvalidbooleanfalseWhether the number field is in an invalid state
isRequiredbooleanfalseWhether the number field is required
classNamestring-Additional CSS classes
animationAnimationRootDisableAll-Animation configuration for number field
onChange(value: number) => void-Handler called when the numeric value changes
...ViewPropsViewProps-All standard React Native View props are supported

AnimationRootDisableAll

Animation configuration for the NumberField root component. Can be:

  • "disable-all": Disable all animations including children (cascades down)
  • undefined: Use default animations

NumberField.Group

proptypedefaultdescription
childrenReact.ReactNode | ((props: NumberFieldGroupRenderProps) => React.ReactNode)-Children elements, or a render function receiving group state
classNamestring-Additional CSS classes
...ViewPropsViewProps-All standard React Native View props are supported

NumberFieldGroupRenderProps

propertytypedescription
numberValuenumberCurrent numeric value (NaN when empty)
displayValuestringDisplay string shown in the input
canIncrementbooleanWhether the value can be incremented (not at max)
canDecrementbooleanWhether the value can be decremented (not at min)
isDisabledbooleanWhether the number field is disabled
isInvalidbooleanWhether the number field is in an invalid state
isRequiredbooleanWhether the number field is required
decrementButtonWidthnumberMeasured width of the decrement button (0 if absent)
incrementButtonWidthnumberMeasured width of the increment button (0 if absent)

NumberField.Input

proptypedefaultdescription
isAutoPaddingActivebooleantrueWhether auto padding is added to avoid overlapping with buttons
autoPaddingAddonnumber12Extra horizontal spacing (in px) between button edge and text content
...InputPropsInputProps-All Input component props are supported

NumberField.DecrementButton

proptypedefaultdescription
childrenReact.ReactNode-Button content; defaults to MinusIcon when omitted
styleStyleProp<ViewStyle>-Style applied to the outer Pressable container
classNamestring-Additional CSS classes for the outer container slot
classNamesElementSlots<DecrementButtonSlots>-Additional CSS classes for individual slots
stylesPartial<Record<DecrementButtonSlots, ViewStyle>>-Styles for individual slots
animationNumberFieldButtonAnimation-Animation configuration for button press scale feedback
isAnimatedStyleActivebooleantrueWhether animated styles are applied to the contentContainer
iconPropsNumberFieldButtonIconProps-Props forwarded to the default icon; ignored with custom children
...PressablePropsPressableProps-All standard React Native Pressable props are supported

ElementSlots<DecrementButtonSlots>

proptypedescription
containerstringCustom class name for the outer Pressable container
contentContainerstringCustom class name for the inner animated content view

styles

proptypedescription
containerViewStyleStyles for the outer Pressable container
contentContainerViewStyleStyles for the inner animated content view

NumberFieldButtonIconProps

proptypedefaultdescription
sizenumber16Icon size in logical pixels
colorstringforegroundIcon fill color; defaults to theme foreground color

NumberFieldButtonAnimation

Animation configuration for increment/decrement button press feedback. Can be:

  • false or "disabled": Disable button press animation
  • undefined: Use default animation
  • object: Custom animation configuration
proptypedefaultdescription
scale.value[number, number][1, 0.9]Scale values [unpressed, pressed]
scale.timingConfigWithTimingConfig{ duration: 150 }Animation timing configuration

NumberField.IncrementButton

proptypedefaultdescription
childrenReact.ReactNode-Button content; defaults to PlusIcon when omitted
styleStyleProp<ViewStyle>-Style applied to the outer Pressable container
classNamestring-Additional CSS classes for the outer container slot
classNamesElementSlots<IncrementButtonSlots>-Additional CSS classes for individual slots
stylesPartial<Record<IncrementButtonSlots, ViewStyle>>-Styles for individual slots
animationNumberFieldButtonAnimation-Animation configuration for button press scale feedback
isAnimatedStyleActivebooleantrueWhether animated styles are applied to the contentContainer
iconPropsNumberFieldButtonIconProps-Props forwarded to the default icon; ignored with custom children
...PressablePropsPressableProps-All standard React Native Pressable props are supported

The IncrementButton shares the same slot structure as DecrementButton. See ElementSlots<DecrementButtonSlots>, styles, NumberFieldButtonIconProps, and NumberFieldButtonAnimation above.

On this page