Number Input
The NumberInput component handles numeric input, providing options for styling via themes and sizes. It also offers options for adding stepper controls, captions, suffixes, tooltips, and error or warning text for the field.
Variations
Disable
Read only
Optional
Without stepper UI
Theme
The NumberInput component accepts a theme prop, which defines the visual state of the input: either success, warning, or danger.
Passing a message to error forces the danger theme, and passing a message to warning forces the warning theme — these override any explicit theme.
Min / Max limits
Integer and decimal values
By default the input accepts decimals. Set integerOnly to block decimal points and restrict entry to whole numbers.
Positive and negative values
Custom steppers
With suffix
With tooltip
tooltipContent is used to display the content of the tooltip. tooltipProps is used to pass additional props to the tooltip.
Orientation
The NumberInput component accepts an optional orientation prop, which defines the layout direction of the input and its label. Available options are horizontal and vertical (default).
Installation
import { NumberInput } from '@harnessio/ui/components'
// ..return ( <NumberInput integerOnly label="Quantity" placeholder="Enter a number" min={0} max={100} defaultValue={1} onChange={(e) => handleQuantityChange(e.target.value)} />)Anatomy
NumberInput is a native <input type="number"> wrapped with a label, optional caption, and stepper controls.
<NumberInput label="Quantity" min={0} max={100} step={1} defaultValue={1} onChange={(e) => handleChange(e.target.value)}/>- Label — associated with the input via
htmlFor; addoptional,labelSuffix, ortooltipContent/tooltipPropsfor extra affordances. - Input — a real numeric input.
value(controlled) ordefaultValue(uncontrolled) sets the number;onChangeis the native change handler, so readevent.target.value. - Stepper controls — up / down buttons rendered in the input’s suffix that call the native step behavior by
step. Hidden whenhideStepperorreadOnlyis set. - Caption / message —
errorshows first, thenwarning, thencaptionbelow the field (in horizontal orientation the caption moves up beside the label).
Best practices
Do
- Set
min,max, andstepto match the real constraints of the value so the steppers and validation behave sensibly. - Use
integerOnlyfor counts and quantities that can’t be fractional. - Provide a
suffix(e.g. a unit) orcaptionwhen the number’s meaning isn’t obvious from the label alone.
Don’t
- Don’t use
NumberInputfor values that aren’t really numbers (phone numbers, IDs, codes) — use a text input so leading zeros and formatting are preserved. - Don’t rely on
integerOnlyalone to guarantee whole numbers on submit — validate the final value as well (see limitations).
Content
- Label the input with the noun it captures (“Quantity”, “Replicas”), not an instruction.
- Keep captions to a short constraint or hint (“Between 0 and 100”).
- Put units in the
suffixrather than the label when space allows.
Accessibility
Keyboard
- The input is a native numeric field: Up / Down arrows increment and decrement by
stepwhen the field is focused. - The stepper buttons are intentionally removed from the tab order (
tabIndex={-1}), so keyboard users step with the arrow keys rather than tabbing to the buttons.
Labeling
- The label is tied to the input with
htmlFor; when noidis supplied one is generated automatically so the association still holds. - The increment / decrement buttons carry
aria-labels (“Increment value” / “Decrement value”).
Focus & states
disabled,readOnly, andoptionalare supported. WhenreadOnlyis set the steppers are hidden along withhideStepper.inputModeis set (numericwhenintegerOnly, otherwisedecimal) so mobile keyboards show the right keys.
Known limitations
integerOnlydoesn’t cover paste. It blocks a typed decimal point but does not sanitize a pasted decimal value, so validate the committed value if whole numbers are required.
Properties
NumberInput
Prop | Required | Default | Type |
|---|---|---|---|
| label | false | string | |
| id | false | string | |
| value | false | number | |
| defaultValue | false | number | |
| onChange | false | React.ChangeEventHandler<HTMLInputElement> | |
| min | false | number | |
| max | false | number | |
| step | false | 1 | number |
| integerOnly | false | false | boolean |
| hideStepper | false | false | boolean |
| theme | false | 'default' | 'default' | 'success' | 'danger' | 'warning' |
| error | false | string | |
| warning | false | string | |
| caption | false | string | |
| placeholder | false | string | |
| disabled | false | false | boolean |
| readOnly | false | false | boolean |
| optional | false | false | boolean |
| size | false | 'md' | 'md' | 'sm' |
| prefix | false | ReactNode | |
| suffix | false | ReactNode | |
| tooltipContent | false | Exclude<ReactNode, boolean | null | undefined> | |
| tooltipProps | false | IconWithTooltipProps | |
| labelSuffix | false | ReactNode | |
| orientation | false | 'vertical' | 'vertical' | 'horizontal' |
| className | false | string | |
| wrapperClassName | false | string |
IconWithTooltipProps
interface IconWithTooltipProps extends Omit<TooltipProps, "children"> { className?: string; /** * If disabled, the tooltip will not be shown */ disabled?: boolean; iconProps?: IconPropsV2;}