- Accordion
- Avatar
- Badge
- Breadcrumb
- Button
- Calendar
- ChatContainer
- ChatInput
- ChatMessage
- ChatMultiChoiceQuestion
- ChatMultiOptionQuestion
- ChatThinking
- Checkbox
- Combobox
- Container
- CurrencyInput
- DistributionSlider
- Drawer
- Dropdown
- FilePicker
- Grid
- Heading
- Image
- Input
- InputGroup
- Label
- Logo
- MapPin
- Markdown
- Modal
- NativeSelect
- NumberInput
- OptionSlider
- OtpInput
- PhoneInput
- Popover
- Progress
- PropertyCalendar
- RadioGroup
- RadioGroupCards
- ResponsiveModal
- ScrollArea
- SearchBar
- SearchBarFallback
- SearchInput
- Select
- Separator
- Spinner
- Switch
- Table
- Tabs
- Text
- Textarea
- TimePicker
- Toast
- Toggle
- ToggleCard
- ToggleGroup
- Toolbar
- Tooltip
NumberInput
A simple counter component with increment and decrement buttons
pnpm add @wandercom/design-system-web
import { NumberInput } from '@wandercom/design-system-web/ui/number-input';
export function Example() {
const [value, setValue] = useState<number | null>(5);
return (
<NumberInput
value={value}
min={0}
max={10}
step={1}
onChange={setValue}
/>
);
}Basic number input with increment and decrement buttons.
Number input displaying a placeholder when value is null.
const [value, setValue] = useState<number | null>(null);
<NumberInput
value={value}
min={0}
max={100}
step={5}
placeholder="Any"
onChange={setValue}
/>Number input with currency symbol prefix.
const [value, setValue] = useState<number | null>(50);
<NumberInput
value={value}
min={0}
max={500}
step={25}
currency="USD"
onChange={setValue}
/>Number input with a custom placeholder text.
const [value, setValue] = useState<number | null>(null);
<NumberInput
value={value}
min={1}
max={10}
step={1}
placeholder="None"
onChange={setValue}
/>Number input demonstrating various currency and locale combinations with proper formatting:
- United States (en-US):
$1,500(comma separator, symbol before) - Germany (de-DE):
1.500 €(period separator, symbol after) - United Kingdom (en-GB):
£1,500(comma separator, symbol before) - Japan (ja-JP):
Â¥1,500(comma separator, symbol before)
import { Label } from '@wandercom/design-system-web/ui/label';
const [usValue, setUsValue] = useState<number | null>(1500);
const [deValue, setDeValue] = useState<number | null>(1500);
const [gbValue, setGbValue] = useState<number | null>(1500);
const [jpValue, setJpValue] = useState<number | null>(1500);
<div className="flex flex-col gap-4">
<div className="flex flex-col gap-2">
<Label htmlFor="us-input">United States (en-US)</Label>
<NumberInput
id="us-input"
value={usValue}
min={0}
max={10000}
step={100}
currency="USD"
locale="en-US"
onChange={setUsValue}
/>
</div>
<div className="flex flex-col gap-2">
<Label htmlFor="de-input">Germany (de-DE)</Label>
<NumberInput
id="de-input"
value={deValue}
min={0}
max={10000}
step={100}
currency="EUR"
locale="de-DE"
onChange={setDeValue}
/>
</div>
<div className="flex flex-col gap-2">
<Label htmlFor="gb-input">United Kingdom (en-GB)</Label>
<NumberInput
id="gb-input"
value={gbValue}
min={0}
max={10000}
step={100}
currency="GBP"
locale="en-GB"
onChange={setGbValue}
/>
</div>
<div className="flex flex-col gap-2">
<Label htmlFor="jp-input">Japan (ja-JP)</Label>
<NumberInput
id="jp-input"
value={jpValue}
min={0}
max={10000}
step={100}
currency="JPY"
locale="ja-JP"
onChange={setJpValue}
/>
</div>
</div>value?:
min?:
max?:
step?:
placeholder?:
currency?:
locale?:
onChange?:
disabled?:
required?:
aria-label?:
aria-labelledby?:
aria-describedby?:
id?:
name?:
decreaseLabel?:
increaseLabel?:
className?:
The − and + buttons are the only interactive controls. The displayed value is a non-interactive element with aria-live="polite" so screen readers announce changes as the user steps the value.
Keyboard Navigation:
Tab- Move focus between the − and + buttonsEnter/Space- Activate the focused button
Screen Reader Support:
- Stepper group is labeled via
aria-label/aria-labelledby - Value updates are announced via
aria-live="polite" - Each button has a descriptive
aria-label("Decrease value" / "Increase value")
Form Integration:
- Optional hidden input for native form submission when
nameprop is provided - Supports
requiredanddisabledstates
Increment/decrement buttons are the only way to change the value. They adjust by the step amount, respecting min and max bounds. When the value is null (placeholder state), pressing increment sets the value to min rather than min + step.
Buttons are disabled when the value reaches the minimum or maximum limit. The decrement button is also disabled while the value is null.
Placeholder display shows custom text when value is null, useful for "Any" or "None" states.
Values are automatically clamped to stay within the min and max range.
International formatting uses Intl.NumberFormat to display numbers with locale-specific thousands separators and currency symbols.