Meet Frontfriend.Your brand. Your rules. Your agents, connected.Explore what’s new
DocumentationNumberField

NumberField

NumberField registry component. Frontfriend-owned on React (upstream shadcn has no React number-field) and mirrored from the Vue Reka UI implementation, so both frameworks expose the same composition and step/clamp behaviour.

Interactive preview

Rendered from the shared Frontfriend stories with React Base, the same preview Studio shows. Styling comes from your Design System; the code below is native to React Aria.

Installation

Complete project setup first. Your configuration must select react/aria and include your Design System ID.

pnpm exec frontfriend download number-field -f react --primitive aria

Review dependencies reported by the downloader and keep your source changes in version control.

Usage

import {
  NumberField,
  NumberFieldContent,
  NumberFieldDecrement,
  NumberFieldInput,
  NumberFieldIncrement,
} from "@/components/ui/number-field";
import * as React from "react";
export default function NumberFieldExample() {
  const [value, setValue] = React.useState<number | undefined>(
    12,
  );
  return (
    <NumberField
      min={0} max={100} step={1} disabled={false}
      value={value}
      onValueChange={setValue}
      className="w-48"
    >
      <NumberFieldContent>
        <NumberFieldDecrement />
        <NumberFieldInput />
        <NumberFieldIncrement />
      </NumberFieldContent>
    </NumberField>
  );
}

Subcomponents

  • NumberField — root; owns the value, min/max/step and disabled state
  • NumberFieldContent — positions the input against the steppers
  • NumberFieldInput — the spinbutton; ArrowUp/Down step, PageUp/Down step by 10, Home/End jump to the bounds
  • NumberFieldIncrement / NumberFieldDecrement — steppers; auto-disable at the bound and repeat on press-and-hold

Examples

Default

import {
  NumberField,
  NumberFieldContent,
  NumberFieldDecrement,
  NumberFieldInput,
  NumberFieldIncrement,
} from "@/components/ui/number-field";
<NumberField defaultValue={12} className="w-40">
  <NumberFieldContent>
    <NumberFieldDecrement />
    <NumberFieldInput />
    <NumberFieldIncrement />
  </NumberFieldContent>
</NumberField>;

Min Max Step

import {
  NumberField,
  NumberFieldContent,
  NumberFieldDecrement,
  NumberFieldInput,
  NumberFieldIncrement,
} from "@/components/ui/number-field";
<NumberField min={0} max={10} step={2} defaultValue={4} className="w-40">
  <NumberFieldContent>
    <NumberFieldDecrement />
    <NumberFieldInput />
    <NumberFieldIncrement />
  </NumberFieldContent>
</NumberField>;

Disabled

import {
  NumberField,
  NumberFieldContent,
  NumberFieldDecrement,
  NumberFieldInput,
  NumberFieldIncrement,
} from "@/components/ui/number-field";
<NumberField defaultValue={12} disabled className="w-40">
  <NumberFieldContent>
    <NumberFieldDecrement />
    <NumberFieldInput />
    <NumberFieldIncrement />
  </NumberFieldContent>
</NumberField>;

Invalid

import {
  NumberField,
  NumberFieldContent,
  NumberFieldDecrement,
  NumberFieldInput,
  NumberFieldIncrement,
} from "@/components/ui/number-field";
<NumberField defaultValue={12} className="w-40">
  <NumberFieldContent>
    <NumberFieldDecrement />
    <NumberFieldInput aria-invalid />
    <NumberFieldIncrement />
  </NumberFieldContent>
</NumberField>;

Formatted

import {
  NumberField,
  NumberFieldContent,
  NumberFieldDecrement,
  NumberFieldInput,
  NumberFieldIncrement,
} from "@/components/ui/number-field";
<NumberField
  defaultValue={1234.5}
  step={0.5}
  formatOptions={{ style: "currency", currency: "EUR" }}
  className="w-48"
>
  <NumberFieldContent>
    <NumberFieldDecrement />
    <NumberFieldInput />
    <NumberFieldIncrement />
  </NumberFieldContent>
</NumberField>;

API reference

Frontfriend-owned props. Native HTML and inherited primitive props remain documented by React Aria.

Prop Type Default Description
defaultValue number —
disabled boolean —
disableWheelChange boolean —
formatOptions Intl.NumberFormatOptions —
invertWheelChange boolean —
locale string —
max number —
min number —
name string —
onValueChange (value: number | undefined) => void —
required boolean —
step number —
stepSnapping boolean —
value number | null —

Configuration determines the actual classes and available styling hooks. See Theming & component configuration before introducing a repeated local override.