> ## Documentation Index
> Fetch the complete documentation index at: https://docs.twenty.com/llms.txt
> Use this file to discover all available pages before exploring further.

# NumberStepper

> Edit a number with optional bounds and increment or decrement buttons.

export const StoryEmbed = ({storyId, title, height = 240}) => <>
    <Tabs>
      <Tab title="Light">
        <iframe title={`${title} (light)`} src={`https://storybook.twenty.com/iframe.html?id=${storyId}&viewMode=story&globals=colorScheme:light`} width="100%" height={height} loading="lazy" style={{
  border: 0
}} />
      </Tab>
      <Tab title="Dark">
        <iframe title={`${title} (dark)`} src={`https://storybook.twenty.com/iframe.html?id=${storyId}&viewMode=story&globals=colorScheme:dark`} width="100%" height={height} loading="lazy" style={{
  border: 0
}} />
      </Tab>
    </Tabs>
    <a href={`https://storybook.twenty.com/?path=/story/${storyId}`}>
      Open in Storybook
    </a>
  </>;

`NumberStepper` is the compact convenience preset built from [NumberField](/ui/primitives/input/number-field). It combines a numeric text input with optional decrement and increment buttons. Import it from `twenty-ui/components/input`. Use `NumberField` when you need locale or formatting options, different modifier steps, scrubbing, or independent part composition.

<StoryEmbed storyId="ui-input-numberstepper--default" title="NumberStepper example" height={180} />

## Uncontrolled value

Use `defaultValue` to set the initial quantity. The input owns subsequent changes.

```tsx theme={null}
import { NumberStepper } from 'twenty-ui/components/input';
import { Field } from 'twenty-ui/primitives/input';

export const QuantityInput = () => (
  <Field.Root>
    <Field.Label>Quantity</Field.Label>
    <NumberStepper name="quantity" defaultValue={3} min={0} max={10} step={1} />
    <Field.Description>Choose up to ten items.</Field.Description>
  </Field.Root>
);
```

## Controlled value

Pass a number or `null` through `value` and update it in `onValueChange` to own the same quantity in React state. The callback receives the next numeric value and event details.

```tsx theme={null}
import { useState } from 'react';
import { NumberStepper } from 'twenty-ui/components/input';
import { Field } from 'twenty-ui/primitives/input';

export const QuantityInput = () => {
  const [quantity, setQuantity] = useState<number | null>(3);

  return (
    <Field.Root>
      <Field.Label>Quantity</Field.Label>
      <NumberStepper
        name="quantity"
        value={quantity}
        onValueChange={setQuantity}
        min={0}
        max={10}
        step={1}
      />
      <Field.Description>Choose up to ten items.</Field.Description>
    </Field.Root>
  );
};
```

Clearing the field reports `null`. Incomplete text such as `-` or `+` remains editable without reporting an invalid number until it is replaced or stepped. By default, parseable numeric edits report the bounded value; the displayed draft is normalized on blur. Values equal to the current value do not call `onValueChange` again.

`onValueCommitted(value, details)` reports the value after an edit is committed: on blur after typing or clearing, on pointer release after a button adjustment, and immediately for keyboard adjustments. Its details contain the native `event` and `reason`. `onValueChange` retains change details, including cancellation methods and the optional stepping direction.

## Application validation

Set `allowOutOfRange` when the application needs the parsed value before applying its own limits or validation. `onValueChange` then receives typed and pasted numbers outside the range. Uncontrolled fields, or controlled fields that accept those values, preserve them on blur. Controlled fields that reject them return to their accepted value on blur. For example, replacing `60` with `45` reports `4` and then `45`, even when `min={30}`. The application can ignore the intermediate value without accidentally saving the minimum.

Buttons and keyboard adjustments still stop at `min` and `max`. Native form validation prevents submission while an accepted value is outside that range. `allowOutOfRange` defaults to `false`.

## Bounds and interaction

`min` and `max` are inclusive. Increment and decrement buttons stop at the matching bound. Arrow Up and Arrow Down adjust the focused input by `step`, which defaults to `1`. Home and End select the corresponding bound when provided; call `event.preventBaseUIHandler()` in `onKeyDown` to keep a key's text editing behavior instead. The same step applies when Shift or Alt is held. Displayed values support up to 15 fraction digits; use a positive step within that precision for decimal adjustments.

Values use Latin digits and show grouping separators from five integer digits, such as `12,500`. Typed and pasted group separators of the browser's locale are accepted.

`step` controls adjustments; it does not round typed values to a step. When `min` is set, native form validation also requires `min` plus a multiple of `step`: with the default `step` of `1`, a typed `2.5` blocks submission. Set `showButtons={false}` for text editing with the same keyboard behavior.

Each button has a default accessible name. Use `decrementLabel` and `incrementLabel` to provide contextual or translated names. Give the input a visible `Field.Label`, `aria-label`, or `aria-labelledby`.

## Forms and focus

Use `name` to include the numeric value in a form. `form` associates it with a form elsewhere in the document. The adjustment buttons use `type="button"`, so adjusting a value does not submit the form. `required` participates in native validation.

Use a controlled `value` when your application needs to reset the field. A native form reset does not reset the numeric state.

`disabled` prevents changes and excludes the value from form submission. `readOnly` prevents changes while keeping the input focusable and its value available to the form.

Native input attributes and handlers, `className`, `style`, `ref`, and `render` apply to the visible text input. The ref receives an `HTMLInputElement`; call `ref.current?.focus()` to focus it. When composing through `render`, forward the supplied props and ref to a native input. Customize the surrounding layout with a separate element, or use the `NumberField.Root` and `NumberField.Group` parts when wrapper access is required. Combine the input with `Field.Description` and `Field.Error` for guidance and validation messages.

The preset deliberately uses compact styling, Latin digits, up to 15 fraction digits, grouping from five integer digits, and the same `step` for ordinary, Shift, and Alt adjustments. These choices apply only to `NumberStepper`. The full `NumberField` primitive retains Base UI's formatting and stepping options.

## Front component renderer

The React and Preact renderer sandboxes support typing, keyboard adjustments, bounds, form values, pointer stepping, and pasting over selected text. The renderer gallery verifies these interactions in both runtimes. As with `NumberField`, pointer adjustments report changes, but the sandbox does not currently deliver the corresponding commit callback on pointer release. Ordinary React hosts retain the complete commit behavior.

## Props

<ParamField body="allowOutOfRange" type="boolean" default="false">
  Allows onValueChange to receive typed and pasted numbers outside the bounds. Native range validation still applies; buttons and keyboard adjustments remain bounded.
</ParamField>

<ParamField body="aria-roledescription" type="string" default="Number field">
  A user-friendly description of the input's role for assistive tech. This is a role
  description, not an accessible name — use `Field.Label` or `aria-label` to name the control.
</ParamField>

<ParamField body="className" type="string | ((state: NumberFieldInputState) => string | undefined)">
  Class applied to the visible input.
</ParamField>

<ParamField body="decrementLabel" type="string" default="Decrease value">
  Accessible name for the decrement button.
</ParamField>

<ParamField body="defaultValue" type="number">
  Initial number when the field owns its value.
</ParamField>

<ParamField body="disabled" type="boolean" default="false">
  Disables the input and both buttons, and omits the form value.
</ParamField>

<ParamField body="form" type="string">
  ID of the form that owns the submitted numeric value.
</ParamField>

<ParamField body="id" type="string">
  ID of the visible input. Generated when omitted.
</ParamField>

<ParamField body="incrementLabel" type="string" default="Increase value">
  Accessible name for the increment button.
</ParamField>

<ParamField body="max" type="number">
  Inclusive maximum. By default, onValueChange reports bounded numbers and out-of-range drafts normalize on blur.
</ParamField>

<ParamField body="min" type="number">
  Inclusive minimum. By default, onValueChange reports bounded numbers and out-of-range drafts normalize on blur.
</ParamField>

<ParamField body="name" type="string">
  Name of the numeric value submitted with a form.
</ParamField>

<ParamField body="onValueChange" type="((value: number | null, eventDetails: NumberFieldRootChangeEventDetails) => void)">
  Called with the next number or null and event details when the numeric value changes. Clearing reports null; incomplete text does not report a number.
</ParamField>

<ParamField body="onValueCommitted" type="((value: number | null, eventDetails: NumberFieldRootCommitEventDetails) => void)">
  Called with the committed number or null and generic event details after an edit is committed. Details contain the native event and reason, without change cancellation methods.
</ParamField>

<ParamField body="readOnly" type="boolean" default="false">
  Prevents numeric changes while keeping the input focusable.
</ParamField>

<ParamField body="ref" type="Ref<HTMLInputElement>">
  Ref to the visible input element.
</ParamField>

<ParamField body="render" type="ReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<DetailedHTMLProps<InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>, NumberFieldInputState>">
  Composes the visible text input with an element or render callback. Forward the supplied props and ref to an input. Use a separate element to customize the surrounding layout.
</ParamField>

<ParamField body="required" type="boolean" default="false">
  Requires a numeric value for native form submission.
</ParamField>

<ParamField body="showButtons" type="boolean" default="true">
  Shows the decrement and increment buttons.
</ParamField>

<ParamField body="step" type="number" default="1">
  Amount added or subtracted by the buttons and arrow keys.
</ParamField>

<ParamField body="style" type="CSSProperties | ((state: NumberFieldInputState) => CSSProperties | undefined)">
  Inline styles applied to the visible input.
</ParamField>

<ParamField body="value" type="number | null">
  Controlled numeric value. Use null for an empty field.
</ParamField>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.