Skip to main content

NumberInput

** Last Built**: September 2, 2025 at 4:19 PM A specialized number input component with step controls, validation, and number formatting options. Follows React Admin patterns and provides enhanced number input functionality.

Overview​

The NumberInput component is designed for numeric data entry with built-in validation, step controls, and accessibility features. It's perfect for forms that require precise numeric input with constraints and user-friendly controls.

Features​

  • Step Controls: Optional up/down buttons for incrementing/decrementing values
  • Validation: Min/max value constraints with automatic enforcement
  • Decimal Support: Configurable decimal places and decimal handling
  • Accessibility: Full ARIA support, keyboard navigation, and screen reader compatibility
  • Theme Integration: Consistent styling with Tailwind CSS
  • TypeScript: Fully typed with comprehensive prop interfaces

Basic Usage​

// Component is available in the live scope
function MyForm() {
const [quantity, setQuantity] = useState(0);
return (
<NumberInput
label='Quantity'
value={quantity}
onChange={e => setQuantity(Number(e.target.value))}
min={0}
max={100}
step={1}
/>
);
}

Props​

| Prop | Type | Default | Description | | ------------------------------------------- | ----------------------------------- | | label | string | - | Label text for the input | | helperText | string | - | Helper text below the input | | error | string | - | Error message to display | | required | boolean | false | Whether the field is required | | size | 'sm' \| 'md' \| 'lg' | 'md' | Input size variant | | loading | boolean | false | Whether to show a loading state | | leftIcon | ReactNode | - | Icon to display on the left side | | rightIcon | ReactNode | - | Icon to display on the right side | | disabled | boolean | false | Whether the input is disabled | | readOnly | boolean | false | Whether the input is read-only | | min | number | - | Minimum value allowed | | max | number | - | Maximum value allowed | | step | number | 1 | Step increment for up/down buttons | | showStepControls | boolean | false | Whether to show step controls | | allowDecimals | boolean | true | Whether to allow decimal values | | decimalPlaces | number | - | Number of decimal places to display | | onStepUp | (current: number, step: number) => number | - | Custom step up handler | | onStepDown | (current: number, step: number) => number | - | Custom step down handler |

Examples​

Basic Number Input​

<NumberInput label='Age' placeholder='Enter your age' min={0} max={120} />

With Step Controls​

<NumberInput label='Quantity' showStepControls step={5} min={0} max={1000} />

Decimal Input with Constraints​

<NumberInput
label='Price'
step={0.01}
allowDecimals
decimalPlaces={2}
min={0}
max={999.99}
showStepControls
/>

Custom Step Handler​

<NumberInput
label='Custom Steps'
showStepControls
step={10}
onStepUp={(current, step) => current + step * 2}
onStepDown={(current, step) => current - step * 2}
/>

With Icons and Loading State​

<NumberInput
label='Population'
leftIcon={<UsersIcon />}
rightIcon={<InfoIcon />}
loading={isLoading}
helperText='Enter the current population'
/>

Error State​

<NumberInput
label='Score'
error='Score must be between 0 and 100'
min={0}
max={100}
/>

Required Field​

<NumberInput
label='Rating'
required
min={1}
max={5}
helperText='Rate from 1 to 5 stars'
/>

Accessibility​

The NumberInput component follows accessibility best practices:

  • Labels: Proper label association with htmlFor attribute
  • ARIA: aria-invalid, aria-describedby for error states and helper text
  • Keyboard Navigation: Full keyboard support for step controls
  • Screen Readers: Proper semantic structure and descriptions
  • Focus Management: Clear focus indicators and focus handling

Validation​

The component automatically enforces validation rules:

  • Min/Max Constraints: Values are automatically clamped to min/max bounds
  • Decimal Handling: Decimal places are enforced when specified
  • Step Validation: Step controls respect min/max constraints
  • Input Filtering: Non-numeric characters are filtered out

Step Controls​

When showStepControls is enabled, the component displays up/down buttons:

  • Increment: Increases value by the specified step
  • Decrement: Decreases value by the specified step
  • Constraint Respect: Buttons automatically disable when reaching min/max limits
  • Custom Logic: Support for custom step up/down handlers

State Management​

The component supports both controlled and uncontrolled modes:

  • Controlled: Use value prop for external state management
  • Uncontrolled: Use defaultValue for internal state management
  • Hybrid: Mix controlled and uncontrolled behavior as needed

Integration with Forms​

The NumberInput component integrates seamlessly with form libraries:

import { useForm } from 'react-hook-form';
function MyForm() {
const { register, handleSubmit } = useForm();
return (
<form onSubmit={handleSubmit(onSubmit)}>
<NumberInput
label='Amount'
{...register('amount', {
required: true,
min: 0,
max: 1000,
})}
/>
<button type='submit'>Submit</button>
</form>
);
}

Best Practices​

When to Use​

  • Numeric Data Entry: Any form requiring numeric input
  • Constrained Values: When you need min/max validation
  • Step-based Input: When users need to increment/decrement values
  • Precise Input: When decimal precision is important

When Not to Use​

  • Free-form Text: Use TextInput instead
  • Simple Numbers: Basic number inputs might be sufficient
  • Complex Calculations: Consider specialized calculator components

Performance Considerations​

  • Step Controls: Only enable when needed to avoid unnecessary re-renders
  • Validation: Min/max constraints are enforced on every change
  • Decimal Handling: Decimal place formatting happens on every input

Migration from React Admin​

If you're migrating from React Admin, the NumberInput component provides similar functionality:

// React Admin
<NumberInput source="quantity" min={0} max={100} />
// React SuperAdmin
<NumberInput
label="Quantity"
min={0}
max={100}
onChange={(e) => setQuantity(Number(e.target.value))}
/>

The main differences are:

  • Explicit onChange handler required
  • Label prop instead of source
  • More flexible validation options
  • Enhanced accessibility features