Propel

Number Field

A bounded numeric input with decrement and increment stepper buttons.

Basic

Show code
import { Icon } from "@makeplane/propel/components/icon";
import { IconButton } from "@makeplane/propel/components/icon-button";
import { NumberField } from "@makeplane/propel/components/number-field";
import { Minus, Plus } from "lucide-react";
import * as React from "react";

export default function BasicDemo() {
  const [value, setValue] = React.useState<number | null>(2);

  return (
    <NumberField
      aria-label="Number of instances"
      magnitude="xl"
      min={1}
      max={64}
      value={value}
      onValueChange={setValue}
      decrement={
        <IconButton
          prominence="ghost"
          tone="neutral"
          magnitude="xl"
          aria-label="Decrease"
          icon={<Icon icon={Minus} />}
        />
      }
      increment={
        <IconButton
          prominence="ghost"
          tone="neutral"
          magnitude="xl"
          aria-label="Increase"
          icon={<Icon icon={Plus} />}
        />
      }
    />
  );
}

Magnitudes

The magnitude axis sets the input height, and each stepper IconButton carries the same magnitude so the group stays flush.

Show code
import { Icon } from "@makeplane/propel/components/icon";
import { IconButton } from "@makeplane/propel/components/icon-button";
import { NumberField } from "@makeplane/propel/components/number-field";
import { Minus, Plus } from "lucide-react";

const MAGNITUDES = ["sm", "md", "lg", "xl"] as const;

export default function MagnitudesDemo() {
  return (
    <div className="flex flex-wrap items-center gap-3">
      {MAGNITUDES.map((magnitude) => (
        <NumberField
          key={magnitude}
          aria-label={`Number of seats (${magnitude})`}
          magnitude={magnitude}
          defaultValue={4}
          min={1}
          max={64}
          decrement={
            <IconButton
              prominence="ghost"
              tone="neutral"
              magnitude={magnitude}
              aria-label={`Decrease (${magnitude})`}
              icon={<Icon icon={Minus} />}
            />
          }
          increment={
            <IconButton
              prominence="ghost"
              tone="neutral"
              magnitude={magnitude}
              aria-label={`Increase (${magnitude})`}
              icon={<Icon icon={Plus} />}
            />
          }
        />
      ))}
    </div>
  );
}

Disabled

Show code
import { Icon } from "@makeplane/propel/components/icon";
import { IconButton } from "@makeplane/propel/components/icon-button";
import { NumberField } from "@makeplane/propel/components/number-field";
import { Minus, Plus } from "lucide-react";

export default function DisabledDemo() {
  return (
    <NumberField
      aria-label="Number of seats"
      magnitude="xl"
      defaultValue={12}
      min={1}
      max={64}
      disabled
      decrement={
        <IconButton
          prominence="ghost"
          tone="neutral"
          magnitude="xl"
          aria-label="Decrease"
          icon={<Icon icon={Minus} />}
        />
      }
      increment={
        <IconButton
          prominence="ghost"
          tone="neutral"
          magnitude="xl"
          aria-label="Increase"
          icon={<Icon icon={Plus} />}
        />
      }
    />
  );
}

Formatted

Pass format (an Intl.NumberFormatOptions) to format the displayed value — here as a currency amount stepped by 50.

Show code
import { Icon } from "@makeplane/propel/components/icon";
import { IconButton } from "@makeplane/propel/components/icon-button";
import { NumberField } from "@makeplane/propel/components/number-field";
import { Minus, Plus } from "lucide-react";
import * as React from "react";

export default function FormattedDemo() {
  const [value, setValue] = React.useState<number | null>(250);

  return (
    <NumberField
      aria-label="Monthly budget"
      magnitude="xl"
      min={0}
      max={10000}
      step={50}
      value={value}
      onValueChange={setValue}
      format={{ style: "currency", currency: "USD", maximumFractionDigits: 0 }}
      decrement={
        <IconButton
          prominence="ghost"
          tone="neutral"
          magnitude="xl"
          aria-label="Decrease"
          icon={<Icon icon={Minus} />}
        />
      }
      increment={
        <IconButton
          prominence="ghost"
          tone="neutral"
          magnitude="xl"
          aria-label="Increase"
          icon={<Icon icon={Plus} />}
        />
      }
    />
  );
}

Installation

import { NumberField } from "@makeplane/propel/components/number-field";

Props

NumberField

PropTypeRequiredDescription
magnitude"sm" | "md" | "lg" | "xl"YesVisual size of the field: controls the input height. Required.
decrementReactElement<unknown, string | JSXElementConstructor<any>>YesThe decrement control (e.g. an `IconButton`), rendered as the field's decrement stepper. It carries its own — localizable — `aria-label`; the field bakes no label or glyph.
incrementReactElement<unknown, string | JSXElementConstructor<any>>YesThe increment control (e.g. an `IconButton`), rendered as the field's increment stepper. It carries its own — localizable — `aria-label`; the field bakes no label or glyph.