--- 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 "