---
name: numeric-input-usage
description: >
Use after component-usage-ux when an app needs @techsio/ui-kit NumericInput
for accessible number entry with Zag.js spinbutton behavior, compound parts,
numeric public values, locale formatting, min/max/step, and token-first
styling.
metadata:
component_version: "1.0.1"
type: "core"
library: "@techsio/ui-kit"
library_version: "0.3.2"
requires: "component-usage-ux zag-compound-components app-token-overrides ux-guidelines"
sources: "libs/ui/src/atoms/numeric-input.tsx libs/ui/src/tokens/components/atoms/_numeric-input.css libs/ui/stories/atoms/numeric-input.stories.tsx libs/ui/src/atoms/numeric-input.figma.ts https://zagjs.com/components/react/number-input"
---
# @techsio/ui-kit NumericInput Usage
Use NumericInput for quantities, percentages, currency-like values, or bounded
numbers where keyboard, wheel, increment/decrement, and validation behavior
matter.
## UX/UI guidelines
House rules come from the `ux-guidelines` skill (writing, formatting, states,
where actions and feedback live). This section applies them to `NumericInput`.
**Use it when**
- Bare numeric controls in compact compositions: cart quantity, inline table editors, stepper fields.
**Use something else when**
| Need | Use instead |
| --- | --- |
| A labelled numeric field | FormNumericInput |
| Approximate values | Slider |
| Numeric identifiers | Input |
**Do**
- Pass the app `locale` — the component defaults to `cs-CZ` (ux-guidelines/formatting#locale-defaults-in-the-kit).
- Use `formatOptions` for currency/percent/unit so the displayed value matches the rest of the UI.
- Set `min`/`max`/`step`; at the limit, disable only the trigger that would exceed it.
- Right-align numeric editors inside numeric table columns.
**Don't**
- Use `type="number"` inputs.
- Clamp silently on blur without feedback.
**Copy and states**
- Trigger labels `Increase quantity` / `Decrease quantity`.
## Setup
```tsx
import { NumericInput } from "@techsio/ui-kit/atoms/numeric-input"
```
Public wrapper props use numbers:
```text
value/defaultValue: number
onChange: (value: number) => void
size: sm | md | lg
locale: string, default cs-CZ
precision, min, max, step, name, disabled, required, invalid
allowMouseWheel, allowOverflow, clampValueOnBlur, spinOnPress, formatOptions
```
## Core Patterns
### Keep the compound anatomy intact
```tsx
```
Do not replace trigger parts with native buttons. The subcomponents spread Zag
part props and use Button/Input tokens.
### Respect wrapper value types
Zag number-input documents string values internally, but this UI-kit wrapper
converts public `number` values to the Zag string format and calls `onChange`
with `valueAsNumber`.
```tsx
const [quantity, setQuantity] = useState(1)
```
### Use locale and precision deliberately
```tsx
```
Use `formatOptions` for currency/percent formatting only after checking that
the output is still a usable input value.
### Use describedBy for external help/error text
```tsx
```
`describedBy` is merged into the input `aria-describedby`.
When `id` is provided, it is also the native input's ID, so labels and form
error summary links can target the editable field.
## Common Mistakes
### HIGH Passing Zag string values to the wrapper
Wrong:
```tsx
```
Correct:
```tsx
```
Source: libs/ui/src/atoms/numeric-input.tsx
### HIGH Custom steppers
Wrong:
```tsx
```
Correct:
```tsx
```
Source: https://zagjs.com/components/react/number-input
### HIGH Inline sizing/color classes
Wrong:
```tsx
```
Correct:
```tsx
```
Source: libs/ui/src/tokens/components/atoms/_numeric-input.css
### MEDIUM Missing min/max semantics
Wrong:
```tsx
```
Correct for a quantity:
```tsx
```
Use min/max/step to express domain constraints, not custom blur handlers.
## Validation Commands
```sh
rg -n "]*type=\"number\"|]*(onValueChange|value=\")" apps
rg -U -n "]*className=.*(bg-|text-|border-|px-|py-)" apps
rg -U -P -n "