NumberField
Number input fields with increment/decrement buttons, validation, and internationalized formatting
Usage
import { NumberField } from '@lenso/ui';"use client";
// Adapted from HeroUI v3.2.6 (e385ac202b2cdb94b1bf6fa76d32c31c8259cc5e), Apache-2.0.import { Label, NumberField, TextField } from "@lenso/ui";import { Controls, styles } from "./parts";
export function Basic() { return ( <TextField name="width" xstyle={styles.field}> <NumberField defaultValue={1024} min={0} name="width"> <Label>Width</Label> <Controls /> </NumberField> </TextField> );}Local adaptation source above. Derived from HeroUI v3.2.6 source.
Anatomy
import {NumberField, Label, Description, FieldError} from '@lenso/ui';
export default () => ( <NumberField> <Label /> <NumberField.Group> <NumberField.DecrementButton /> <NumberField.Input /> <NumberField.IncrementButton /> </NumberField.Group> <Description /> <FieldError /> </NumberField>)NumberField allows users to enter numeric values with optional increment/decrement buttons. It supports internationalized formatting, validation, and keyboard navigation.
Examples
Variants
The NumberField component supports two visual variants:
primary(default) - Standard styling with shadow, suitable for most use casessecondary- Lower emphasis variant without shadow, suitable for use in Surface components
"use client";// Adapted from HeroUI v3.2.6 (e385ac202b2cdb94b1bf6fa76d32c31c8259cc5e), Apache-2.0.import { Label, NumberField, TextField } from "@lenso/ui";import * as stylex from "@stylexjs/stylex";import { Controls, styles } from "./parts";
export function Variants() { return ( <div {...stylex.props(styles.column)}> {(["primary", "secondary"] as const).map((variant) => ( <TextField key={variant} name={`${variant}-width`}> <NumberField defaultValue={100} min={0} name={`${variant}-width`} variant={variant}> <Label>{variant === "primary" ? "Primary variant" : "Secondary variant"}</Label> <Controls /> </NumberField> </TextField> ))} </div> );}Local adaptation source above. Derived from HeroUI v3.2.6 source.
In Surface
When used inside a Surface component, use variant="secondary" to apply the lower emphasis variant suitable for surface backgrounds.
"use client";// Adapted from HeroUI v3.2.6 (e385ac202b2cdb94b1bf6fa76d32c31c8259cc5e), Apache-2.0.import { Description, Label, NumberField, Surface, TextField } from "@lenso/ui";import { Controls, styles } from "./parts";
export function OnSurface() { return ( <Surface xstyle={styles.surface}> <TextField name="width"> <NumberField defaultValue={1024} min={0} name="width" variant="secondary"> <Label>Width</Label> <Controls fullWidth /> <Description>Enter the width in pixels</Description> </NumberField> </TextField> <TextField name="percentage"> <NumberField defaultValue={0.5} format={{ style: "percent" }} min={0} max={1} name="percentage" step={0.1} variant="secondary" > <Label>Percentage</Label> <Controls fullWidth /> <Description>Value must be between 0 and 100</Description> </NumberField> </TextField> </Surface> );}Local adaptation source above. Derived from HeroUI v3.2.6 source.
With Description
"use client";// Adapted from HeroUI v3.2.6 (e385ac202b2cdb94b1bf6fa76d32c31c8259cc5e), Apache-2.0.import { Description, Label, NumberField, TextField } from "@lenso/ui";import * as stylex from "@stylexjs/stylex";import { Controls, styles } from "./parts";
export function WithDescription() { return ( <div {...stylex.props(styles.column)}> <TextField name="width"> <NumberField defaultValue={1024} min={0} name="width"> <Label>Width</Label> <Controls /> <Description>Enter the width in pixels</Description> </NumberField> </TextField> <TextField name="percentage"> <NumberField defaultValue={0.5} format={{ style: "percent" }} min={0} max={1} name="percentage" step={0.1} > <Label>Percentage</Label> <Controls /> <Description>Value must be between 0 and 100</Description> </NumberField> </TextField> </div> );}Local adaptation source above. Derived from HeroUI v3.2.6 source.
Required Field
"use client";// Adapted from HeroUI v3.2.6 (e385ac202b2cdb94b1bf6fa76d32c31c8259cc5e), Apache-2.0.import { Description, Label, NumberField, TextField } from "@lenso/ui";import * as stylex from "@stylexjs/stylex";import { Controls, styles } from "./parts";
export function Required() { return ( <div {...stylex.props(styles.column)}> <TextField name="quantity"> <NumberField required min={0} name="quantity"> <Label required>Quantity</Label> <Controls /> </NumberField> </TextField> <TextField name="rating"> <NumberField required defaultValue={1} min={1} max={10} name="rating"> <Label required>Rating</Label> <Controls /> <Description>Rate from 1 to 10</Description> </NumberField> </TextField> </div> );}Local adaptation source above. Derived from HeroUI v3.2.6 source.
Disabled State
"use client";// Adapted from HeroUI v3.2.6 (e385ac202b2cdb94b1bf6fa76d32c31c8259cc5e), Apache-2.0.import { Description, Label, NumberField, TextField } from "@lenso/ui";import * as stylex from "@stylexjs/stylex";import { Controls, styles } from "./parts";
export function Disabled() { return ( <div {...stylex.props(styles.column)}> <TextField disabled name="width"> <NumberField disabled defaultValue={1024} min={0} name="width"> <Label>Width</Label> <Controls /> <Description>Enter the width in pixels</Description> </NumberField> </TextField> <TextField disabled name="percentage"> <NumberField disabled defaultValue={0.5} format={{ style: "percent" }} min={0} max={1} name="percentage" step={0.1} > <Label>Percentage</Label> <Controls /> <Description>Value must be between 0 and 100</Description> </NumberField> </TextField> </div> );}Local adaptation source above. Derived from HeroUI v3.2.6 source.
Full Width
"use client";// Adapted from HeroUI v3.2.6 (e385ac202b2cdb94b1bf6fa76d32c31c8259cc5e), Apache-2.0.import { Label, NumberField, TextField } from "@lenso/ui";import * as stylex from "@stylexjs/stylex";import { styles } from "./parts";
export function FullWidth() { return ( <div {...stylex.props(styles.wide)}> <TextField name="width" fullWidth> <NumberField fullWidth defaultValue={1024} min={0} name="width"> <Label>Width</Label> <NumberField.Group> <NumberField.DecrementButton /> <NumberField.Input /> <NumberField.IncrementButton /> </NumberField.Group> </NumberField> </TextField> </div> );}Local adaptation source above. Derived from HeroUI v3.2.6 source.
Validation
Use isInvalid together with FieldError to surface validation messages.
"use client";// Adapted from HeroUI v3.2.6 (e385ac202b2cdb94b1bf6fa76d32c31c8259cc5e), Apache-2.0.import { FieldError, Label, NumberField, TextField } from "@lenso/ui";import * as stylex from "@stylexjs/stylex";import { Controls, styles } from "./parts";
export function Validation() { return ( <div {...stylex.props(styles.column)}> <TextField invalid name="quantity"> <NumberField required min={0} name="quantity" value={-5} allowOutOfRange> <Label required>Quantity</Label> <Controls /> <FieldError match>Quantity must be greater than or equal to 0</FieldError> </NumberField> </TextField> <TextField invalid name="percentage"> <NumberField format={{ style: "percent" }} min={0} max={1} name="percentage" step={0.1} value={1.5} allowOutOfRange > <Label>Percentage</Label> <Controls /> <FieldError match>Percentage must be between 0 and 100</FieldError> </NumberField> </TextField> </div> );}Local adaptation source above. Derived from HeroUI v3.2.6 source.
Controlled
Control the value to synchronize with other components or perform custom formatting.
"use client";// Adapted from HeroUI v3.2.6 (e385ac202b2cdb94b1bf6fa76d32c31c8259cc5e), Apache-2.0.import { Button, Description, Label, NumberField, TextField } from "@lenso/ui";import { useState } from "react";import * as stylex from "@stylexjs/stylex";import { Controls, styles } from "./parts";
export function Controlled() { const [value, setValue] = useState<number | null>(1024); return ( <div {...stylex.props(styles.column)}> <TextField name="width"> <NumberField min={0} name="width" value={value} onValueChange={setValue}> <Label>Width</Label> <Controls /> <Description>Current value: {value}</Description> </NumberField> </TextField> <div {...stylex.props(styles.row)}> <Button variant="tertiary" onClick={() => setValue(0)}> Reset to 0 </Button> <Button variant="tertiary" onClick={() => setValue(2048)}> Set to 2048 </Button> </div> </div> );}Local adaptation source above. Derived from HeroUI v3.2.6 source.
Step Values
Configure increment/decrement step values for precise control.
"use client";// Adapted from HeroUI v3.2.6 (e385ac202b2cdb94b1bf6fa76d32c31c8259cc5e), Apache-2.0.import { Description, Label, NumberField, TextField } from "@lenso/ui";import * as stylex from "@stylexjs/stylex";import { Controls, styles } from "./parts";
export function WithStep() { return ( <div {...stylex.props(styles.column)}> {[1, 5, 10].map((step) => ( <TextField key={step} name={`step${step}`}> <NumberField defaultValue={0} min={0} max={100} step={step} name={`step${step}`}> <Label>Step: {step}</Label> <Controls /> <Description>Increments by {step}</Description> </NumberField> </TextField> ))} </div> );}Local adaptation source above. Derived from HeroUI v3.2.6 source.
Format Options
Format numbers as currency, percentages, decimals, or units with internationalization support.
"use client";// Adapted from HeroUI v3.2.6 (e385ac202b2cdb94b1bf6fa76d32c31c8259cc5e), Apache-2.0.import { Description, Label, NumberField, TextField } from "@lenso/ui";import * as stylex from "@stylexjs/stylex";import { Controls, styles } from "./parts";
const formats: { name: string; label: string; description: string; value: number; format: Intl.NumberFormatOptions; max?: number; step?: number;}[] = [ { name: "currency-eur", label: "Currency (EUR - Accounting)", description: "Accounting format with EUR currency", value: 99, format: { currency: "EUR", currencySign: "accounting", style: "currency" }, }, { name: "currency-usd", label: "Currency (USD)", description: "Standard USD currency format", value: 99.99, format: { currency: "USD", style: "currency" }, }, { name: "percentage", label: "Percentage", description: "Percentage format (0-1, where 0.5 = 50%)", value: 0.5, format: { style: "percent" }, max: 1, step: 0.01, }, { name: "decimal", label: "Decimal (2 decimal places)", description: "Decimal format with 2 decimal places", value: 1234.56, format: { maximumFractionDigits: 2, minimumFractionDigits: 2, style: "decimal" }, }, { name: "unit", label: "Unit (Kilograms)", description: "Unit format with kilograms", value: 1000, format: { style: "unit", unit: "kilogram", unitDisplay: "short" }, },];
export function WithFormatOptions() { return ( <div {...stylex.props(styles.column)}> {formats.map((item) => ( <TextField key={item.name} name={item.name}> <NumberField defaultValue={item.value} min={0} max={item.max} name={item.name} format={item.format} step={item.step} > <Label>{item.label}</Label> <Controls /> <Description>{item.description}</Description> </NumberField> </TextField> ))} </div> );}Local adaptation source above. Derived from HeroUI v3.2.6 source.
Form Example
Complete form integration with validation and submission handling.
"use client";// Adapted from HeroUI v3.2.6 (e385ac202b2cdb94b1bf6fa76d32c31c8259cc5e), Apache-2.0.import { Button, Description, FieldError, Form, Label, NumberField, Spinner, TextField,} from "@lenso/ui";import { useState, type FormEvent } from "react";import { Controls, styles } from "./parts";
export function FormExample() { const [value, setValue] = useState<number | null>(null); const [isSubmitting, setIsSubmitting] = useState(false); const stockAvailable = 3; const isOutOfStock = value !== null && value > stockAvailable; const handleSubmit = (event: FormEvent<HTMLFormElement>) => { event.preventDefault(); if (value === null || value < 1 || value > stockAvailable || isSubmitting) return; setIsSubmitting(true); setTimeout(() => { console.log("Order submitted:", { quantity: value }); setValue(null); setIsSubmitting(false); }, 1500); }; return ( <Form xstyle={styles.form} onSubmit={handleSubmit}> <TextField name="quantity" invalid={isOutOfStock} validationMode="onChange"> <NumberField required min={1} max={5} name="quantity" value={value} onValueChange={setValue} > <Label required>Order quantity</Label> <Controls /> {isOutOfStock ? ( <FieldError match>Only {stockAvailable} items left in stock</FieldError> ) : ( <Description>Only {stockAvailable} items available</Description> )} </NumberField> </TextField> <Button xstyle={styles.full} disabled={value === null || value < 1 || value > stockAvailable} isLoading={isSubmitting} type="submit" variant="primary" > {isSubmitting ? ( <> <Spinner color="current" size="sm" /> Processing... </> ) : ( "Place Order" )} </Button> </Form> );}Local adaptation source above. Derived from HeroUI v3.2.6 source.
With Validation
Implement custom validation logic with controlled values.
"use client";// Adapted from HeroUI v3.2.6 (e385ac202b2cdb94b1bf6fa76d32c31c8259cc5e), Apache-2.0.import { Description, FieldError, Label, NumberField, TextField } from "@lenso/ui";import { useState } from "react";import { Controls, styles } from "./parts";
export function WithValidation() { const [value, setValue] = useState<number | null>(null); const isInvalid = value !== null && (value < 0 || value > 1); return ( <TextField invalid={isInvalid} name="percentage" validationMode="onChange" xstyle={styles.field} > <NumberField required format={{ style: "percent" }} min={0} max={1} name="percentage" step={0.1} value={value} onValueChange={setValue} allowOutOfRange > <Label required>Percentage</Label> <Controls /> {isInvalid ? ( <FieldError match>Percentage must be between 0 and 100</FieldError> ) : ( <Description>Enter a value between 0 and 100</Description> )} </NumberField> </TextField> );}Local adaptation source above. Derived from HeroUI v3.2.6 source.
Custom Icons
Customize the increment and decrement button icons.
"use client";// Adapted from HeroUI v3.2.6 (e385ac202b2cdb94b1bf6fa76d32c31c8259cc5e), Apache-2.0.import { Description, Label, NumberField, TextField } from "@lenso/ui";import { styles } from "./parts";
export function CustomIcons() { return ( <TextField name="width" xstyle={styles.field}> <NumberField defaultValue={1024} min={0} name="width"> <Label>Width (Custom Icons)</Label> <NumberField.Group> <NumberField.DecrementButton> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" > <path clipRule="evenodd" d="M6.75 11a4.25 4.25 0 1 0 0-8.5a4.25 4.25 0 0 0 0 8.5m0 1.5a5.73 5.73 0 0 0 3.501-1.188l2.719 2.718a.75.75 0 1 0 1.06-1.06l-2.718-2.719A5.75 5.75 0 1 0 6.75 12.5m-2-6.5a.75.75 0 0 0 0 1.5h4a.75.75 0 0 0 0-1.5z" fill="currentColor" fillRule="evenodd" /> </svg> </NumberField.DecrementButton> <NumberField.Input xstyle={styles.input} /> <NumberField.IncrementButton> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" > <path clipRule="evenodd" d="M6.75 11a4.25 4.25 0 1 0 0-8.5a4.25 4.25 0 0 0 0 8.5m0 1.5a5.73 5.73 0 0 0 3.501-1.188l2.719 2.718a.75.75 0 1 0 1.06-1.06l-2.718-2.719A5.75 5.75 0 1 0 6.75 12.5m.75-7.75a.75.75 0 0 0-1.5 0V6H4.75a.75.75 0 0 0 0 1.5H6v1.25a.75.75 0 0 0 1.5 0V7.5h1.25a.75.75 0 0 0 0-1.5H7.5z" fill="currentColor" fillRule="evenodd" /> </svg> </NumberField.IncrementButton> </NumberField.Group> <Description>Custom icon children</Description> </NumberField> </TextField> );}Local adaptation source above. Derived from HeroUI v3.2.6 source.
With Chevrons
Use chevron icons in a vertical layout for a different visual style.
"use client";// Adapted from HeroUI v3.2.6 (e385ac202b2cdb94b1bf6fa76d32c31c8259cc5e), Apache-2.0.import { Label, NumberField, TextField } from "@lenso/ui";import * as stylex from "@stylexjs/stylex";import { styles } from "./parts";
export function WithChevrons() { return ( <TextField name="amount" xstyle={styles.field}> <NumberField defaultValue={99} min={0} name="amount" format={{ currency: "EUR", currencySign: "accounting", style: "currency" }} > <Label>Number field with chevrons</Label> <NumberField.Group> <NumberField.Input xstyle={styles.flexInput} /> <div {...stylex.props(styles.chevrons)}> <NumberField.IncrementButton xstyle={[styles.chevronButton, styles.up]}> <svg aria-hidden="true" height="11" viewBox="0 0 16 16" width="11" xmlns="http://www.w3.org/2000/svg" > <path clipRule="evenodd" d="M13.03 10.53a.75.75 0 0 1-1.06 0L8 6.56l-3.97 3.97a.75.75 0 1 1-1.06-1.06l4.5-4.5a.75.75 0 0 1 1.06 0l4.5 4.5a.75.75 0 0 1 0 1.06" fill="currentColor" fillRule="evenodd" /> </svg> </NumberField.IncrementButton> <NumberField.DecrementButton xstyle={[styles.chevronButton, styles.down]}> <svg aria-hidden="true" height="11" viewBox="0 0 16 16" width="11" xmlns="http://www.w3.org/2000/svg" > <path clipRule="evenodd" d="M2.97 5.47a.75.75 0 0 1 1.06 0L8 9.44l3.97-3.97a.75.75 0 1 1 1.06 1.06l-4.5 4.5a.75.75 0 0 1-1.06 0l-4.5-4.5a.75.75 0 0 1 0-1.06" fill="currentColor" fillRule="evenodd" /> </svg> </NumberField.DecrementButton> </div> </NumberField.Group> </NumberField> </TextField> );}Local adaptation source above. Derived from HeroUI v3.2.6 source.
Render Function
"use client";// Adapted from HeroUI v3.2.6 (e385ac202b2cdb94b1bf6fa76d32c31c8259cc5e), Apache-2.0.import { Label, NumberField, TextField } from "@lenso/ui";import { Controls, styles } from "./parts";
export function RenderFunction() { return ( <TextField name="width" xstyle={styles.field}> <NumberField defaultValue={1024} min={0} name="width" render={(props) => <div {...props} data-custom="foo" />} > <Label>Width</Label> <Controls /> </NumberField> </TextField> );}Local adaptation source above. Derived from HeroUI v3.2.6 source.
Customization
Tailwind CSS
"use client";// Adapted from HeroUI v3.2.6 (e385ac202b2cdb94b1bf6fa76d32c31c8259cc5e), Apache-2.0.import { Label, NumberField, TextField } from "@lenso/ui";import { styles } from "./parts";
export function CustomStyles() { return ( <TextField name="guests" xstyle={styles.guests}> <NumberField defaultValue={2} min={1} name="guests" variant="secondary"> <Label xstyle={styles.label}>Guests</Label> <NumberField.Group xstyle={styles.customGroup}> <NumberField.DecrementButton xstyle={styles.customButton} /> <NumberField.Input xstyle={styles.customInput} /> <NumberField.IncrementButton xstyle={styles.customButton} /> </NumberField.Group> </NumberField> </TextField> );}Local adaptation source above. Derived from HeroUI v3.2.6 source.
Global CSS
NumberField uses CSS classes that can be customized. Override the component classes to match your design system.
@layer components { .number-field { @apply flex flex-col gap-1; }
/* When invalid, the description is hidden automatically */ .number-field[data-invalid="true"] [data-slot="description"], .number-field[aria-invalid="true"] [data-slot="description"] { @apply hidden; }
.number-field__group { @apply bg-field text-field-foreground shadow-field rounded-field inline-flex h-9 items-center overflow-hidden border; }
.number-field__input { @apply flex-1 rounded-none border-0 bg-transparent px-3 py-2 tabular-nums; }
.number-field__increment-button, .number-field__decrement-button { @apply flex h-full w-10 items-center justify-center rounded-none bg-transparent; }}Styling Reference
HeroUI follows the BEM methodology to ensure component variants and states are reusable and easy to customize.
CSS Classes
Base Classes [!toc]
.number-field– Root container with minimal styling (flex flex-col gap-1).number-field__group– Container for input and buttons with border and background styling.number-field__input– The numeric input field.number-field__increment-button– Button to increment the value.number-field__decrement-button– Button to decrement the value
Variant Classes [!toc]
.number-field--primary– Primary variant with shadow (default).number-field--secondary– Secondary variant without shadow, suitable for use in surfaces
Note: Child components (Label, Description, FieldError) have their own CSS classes and styling. See their respective documentation for customization options.
Interactive States
NumberField automatically manages these data attributes based on its state:
- Invalid:
[data-invalid="true"]or[aria-invalid="true"]- Automatically hides the description slot when invalid - Disabled:
[data-disabled="true"]- Applied whenisDisabledis true - Focus Within:
[data-focus-within="true"]- Applied when the input or buttons are focused - Focus Visible:
[data-focus-visible="true"]- Applied when focus is visible (keyboard navigation) - Hovered:
[data-hovered="true"]- Applied when hovering over buttons
Additional attributes are available through render props (see NumberFieldRenderProps below).
API Reference
NumberField
NumberField inherits all props from React Aria's NumberField component.
Base Props
| Prop | Type | Default | Description |
|---|---|---|---|
children | React.ReactNode | (values: NumberFieldRenderProps) => React.ReactNode | - | Child components (Label, Group, Input, etc.) or render function. |
className | string | (values: NumberFieldRenderProps) => string | - | CSS classes for styling, supports render props. |
style | React.CSSProperties | (values: NumberFieldRenderProps) => React.CSSProperties | - | Inline styles, supports render props. |
fullWidth | boolean | false | Whether the number field should take full width of its container |
id | string | - | The element's unique identifier. |
variant | "primary" | "secondary" | "primary" | Visual variant of the component. primary is the default style with shadow. secondary is a lower emphasis variant without shadow, suitable for use in surfaces. |
render | DOMRenderFunction<keyof React.JSX.IntrinsicElements, NumberFieldRenderProps> | - | Overrides the default DOM element with a custom render function. |
Value Props
| Prop | Type | Default | Description |
|---|---|---|---|
value | number | - | Current value (controlled). |
defaultValue | number | - | Default value (uncontrolled). |
onChange | (value: number | undefined) => void | - | Handler called when the value changes. |
Formatting Props
| Prop | Type | Default | Description |
|---|---|---|---|
formatOptions | Intl.NumberFormatOptions | - | Options for formatting numbers (currency, percent, decimal, unit). |
locale | string | - | Locale for number formatting. |
Validation Props
| Prop | Type | Default | Description |
|---|---|---|---|
isRequired | boolean | false | Whether user input is required before form submission. |
isInvalid | boolean | - | Whether the value is invalid. |
validate | (value: number) => ValidationError | true | null | undefined | - | Custom validation function. |
validationBehavior | 'native' | 'aria' | 'native' | Whether to use native HTML form validation or ARIA attributes. |
validationErrors | string[] | - | Server-side validation errors. |
Range Props
| Prop | Type | Default | Description |
|---|---|---|---|
minValue | number | - | Minimum allowed value. |
maxValue | number | - | Maximum allowed value. |
step | number | 1 | Step value for increment/decrement operations. |
State Props
| Prop | Type | Default | Description |
|---|---|---|---|
isDisabled | boolean | - | Whether the input is disabled. |
isReadOnly | boolean | - | Whether the input can be selected but not changed. |
Form Props
| Prop | Type | Default | Description |
|---|---|---|---|
name | string | - | Name of the input element, for HTML form submission. |
autoFocus | boolean | - | Whether the element should receive focus on render. |
Accessibility Props
| Prop | Type | Default | Description |
|---|---|---|---|
aria-label | string | - | Accessibility label when no visible label is present. |
aria-labelledby | string | - | ID of elements that label this field. |
aria-describedby | string | - | ID of elements that describe this field. |
aria-details | string | - | ID of elements with additional details. |
Composition Components
NumberField works with these separate components that should be imported and used directly:
- NumberField.Group - Container for input and buttons
- NumberField.Input - The numeric input field
- NumberField.IncrementButton - Button to increment the value
- NumberField.DecrementButton - Button to decrement the value
- Label - Field label component from
@lenso/ui - Description - Helper text component from
@lenso/ui - FieldError - Validation error message from
@lenso/ui
Each of these components has its own props API. Use them directly within NumberField for composition:
<NumberField isRequired isInvalid={hasError} minValue={0} maxValue={100}> <Label>Quantity</Label> <NumberField.Group> <NumberField.DecrementButton /> <NumberField.Input /> <NumberField.IncrementButton /> </NumberField.Group> <Description>Enter a value between 0 and 100</Description> <FieldError>Value must be between 0 and 100</FieldError></NumberField>NumberField.Group Props
NumberField.Group inherits props from React Aria's Group component.
| Prop | Type | Default | Description |
|---|---|---|---|
children | React.ReactNode | (values: GroupRenderProps) => React.ReactNode | - | Child components (Input, Buttons) or render function. |
className | string | (values: GroupRenderProps) => string | - | CSS classes for styling. |
NumberField.Input Props
NumberField.Input inherits props from React Aria's Input component.
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | - | CSS classes for styling. |
variant | "primary" | "secondary" | "primary" | Visual variant of the input. primary is the default style with shadow. secondary is a lower emphasis variant without shadow, suitable for use in surfaces. |
NumberField.IncrementButton Props
NumberField.IncrementButton inherits props from React Aria's Button component.
| Prop | Type | Default | Description |
|---|---|---|---|
children | React.ReactNode | <IconPlus /> | Icon or content for the button. Defaults to plus icon. |
className | string | - | CSS classes for styling. |
slot | "increment" | "increment" | Must be set to "increment" (automatically set). |
NumberField.DecrementButton Props
NumberField.DecrementButton inherits props from React Aria's Button component.
| Prop | Type | Default | Description |
|---|---|---|---|
children | React.ReactNode | <IconMinus /> | Icon or content for the button. Defaults to minus icon. |
className | string | - | CSS classes for styling. |
slot | "decrement" | "decrement" | Must be set to "decrement" (automatically set). |
Render Props
When using render props with className, style, or children, these values are available:
| Prop | Type | Description |
|---|---|---|
isDisabled | boolean | Whether the field is disabled. |
isInvalid | boolean | Whether the field is currently invalid. |
isReadOnly | boolean | Whether the field is read-only. |
isRequired | boolean | Whether the field is required. |
isFocused | boolean | Whether the field is currently focused (DEPRECATED - use isFocusWithin). |
isFocusWithin | boolean | Whether any child element is focused. |
isFocusVisible | boolean | Whether focus is visible (keyboard navigation). |
value | number | undefined | Current value. |
minValue | number | undefined | Minimum allowed value. |
maxValue | number | undefined | Maximum allowed value. |
step | number | Step value for increment/decrement. |
Related Showcases
See upstream NumberField showcases. Product showcases are not part of the local component runtime.