XDSNumberInput@xds/core · NumberInput
Preview coming soon

Usage

A form input for numeric values with built-in validation, min/max constraints, and step controls. Use NumberInput for quantities, measurements, percentages, and similar inputs.

Best practices

GuidancePractices
DoSet min, max, and step to guide users toward valid values.
DoShow units (e.g. "%" or "GB") so users know what the number represents.
Don'tUse NumberInput for free-form text that happens to contain numbers — use TextInput instead.
Don'tSet both isOptional and isRequired on the same field.

Anatomy

ElementDescription
LabelrequiredThe label for the number input.
DescriptionAdditional description text below the label.
IconAn optional icon within the input.
PlaceholderPlaceholder text shown when the input is empty.
SpinnerIncrement and decrement controls for the value.

Import

ts
import {XDSNumberInput} from '@xds/core/NumberInput'

Props

PropTypeDescription
labelrequired
stringLabel text for the input (always rendered for accessibility).
valuerequired
number | null | undefinedCurrent value of the input.
onChangerequired
(value: number) => voidCallback fired when input value changes (only on valid input).
size
'sm' | 'md' | 'lg' (default: 'md')Size variant.
isLabelHidden
booleanVisually hide the label (still accessible to screen readers).
description
stringDescription text displayed between the label and input.
isOptional
booleanWhether the field is optional (mutually exclusive with isRequired).
isRequired
booleanWhether the field is required (mutually exclusive with isOptional).
isDisabled
booleanWhether the input is disabled.
placeholder
stringPlaceholder text.
labelTooltip
stringTooltip text to display in an info icon at the end of the label.
startIcon
XDSIconTypeIcon to display at the start of the input. See `npx xds docs icons` for valid semantic names.
labelIcon
XDSIconTypeIcon to display before the label text. See `npx xds docs icons` for valid semantic names.
status
{type: 'error' | 'warning' | 'success', message?: string}Validation status with optional message.
min
number | nullMinimum value allowed.
max
number | nullMaximum value allowed.
step
number | null (default: 1)Step increment for the input.
units
string | nullUnits text to display at the end of the input (e.g., "%" or "GB").
isIntegerOnly
booleanOnly allow integer values (no floating point).
hasClear
boolean (default: false)Shows a clear (×) button when the input has a value. When true, the onChange callback also accepts null to signal the user cleared the input.
htmlName
stringHTML name attribute for form submissions.
autoComplete
stringHTML autocomplete attribute.
hasAutoFocus
booleanWhether to focus the input on mount.
onFocus
(e: FocusEvent<HTMLInputElement>) => voidCallback fired when the input receives focus.
onBlur
(e: FocusEvent<HTMLInputElement>) => voidCallback fired when the input loses focus.
onEnter
() => voidCallback fired when the user presses the Enter key.

Examples

Common configurations, variations, and states.
NumberInput — ClearableNumber input with a clear button, unit suffix, and min/max constraint
tsx
'use client';
import {useState} from 'react';
import {XDSNumberInput} from '@xds/core/NumberInput';
import {XDSCenter} from '@xds/core/Center';
export default function NumberInputClearableNumberInput() {
const [value, setValue] = useState<number | null>(75);
return (
<XDSCenter width={300}>
<XDSNumberInput
label="Progress"
units="%"
min={0}
max={100}
value={value}
onChange={setValue}
hasClear
/>
</XDSCenter>
);
}
NumberInput — Range ConstrainedNumber input with min/max boundaries and a helper description
tsx
'use client';
import {useState} from 'react';
import {XDSNumberInput} from '@xds/core/NumberInput';
import {XDSCenter} from '@xds/core/Center';
export default function NumberInputRangeNumberInput() {
const [value, setValue] = useState<number | null>(3);
return (
<XDSCenter width={300}>
<XDSNumberInput
label="Team Size"
placeholder="1–50"
min={1}
max={50}
description="Number of people on the team"
value={value}
onChange={setValue}
/>
</XDSCenter>
);
}
NumberInput — Status VariantsNumber inputs showing error, warning, and success validation states
tsx
'use client';
import {useState} from 'react';
import {XDSNumberInput} from '@xds/core/NumberInput';
import {XDSVStack} from '@xds/core/Stack';
import {XDSCenter} from '@xds/core/Center';
export default function NumberInputStatuses() {
const [error, setError] = useState<number | null>(-5);
const [warning, setWarning] = useState<number | null>(150);
const [success, setSuccess] = useState<number | null>(25);
return (
<XDSCenter width={300}>
<XDSVStack gap={4}>
<XDSNumberInput
label="Budget"
value={error}
onChange={setError}
status={{type: 'error', message: 'Must be a positive amount'}}
/>
<XDSNumberInput
label="Headcount"
value={warning}
onChange={setWarning}
status={{type: 'warning', message: 'Exceeds typical team size'}}
/>
<XDSNumberInput
label="Completion"
units="%"
value={success}
onChange={setSuccess}
status={{type: 'success', message: 'On track'}}
/>
</XDSVStack>
</XDSCenter>
);
}
NumberInput — With UnitsNumber input with a percentage unit suffix and valid range
tsx
'use client';
import {useState} from 'react';
import {XDSNumberInput} from '@xds/core/NumberInput';
import {XDSCenter} from '@xds/core/Center';
export default function NumberInputWithUnits() {
const [value, setValue] = useState<number | null>(50);
return (
<XDSCenter width={300}>
<XDSNumberInput
label="Discount"
placeholder="Enter discount"
min={0}
max={100}
units="%"
value={value}
onChange={setValue}
/>
</XDSCenter>
);
}

Showcase source

tsx
import {XDSNumberInput} from '@xds/core/NumberInput';
export default function NumberInputShowcase() {
return (
<div style={{maxWidth: 300}}>
<XDSNumberInput
label="Quantity"
placeholder="Enter quantity"
value={0}
onChange={() => {}}
/>
</div>
);
}