Sophic Interface Systems
Components

Number Input

Enter an amount — raw or format-as-you-type, with optional currency, Max, and available balance.

€

Unformatted string — Houston day counts, app-owned parsing.

value
—
€

Thousands separators and decimal limits as you type.

formattedValue
—
value
—
floatValue
—

You might be looking for:

Modes

NumberInput has two modes, controlled by whether you pass format:

Raw (default)Formatted (format set)
Controlvalue + onChangevalue + onValueChange
What the user typesStored as-isMasked with separators / decimal limits
Typical useHouston admin, app-owned parsingPortal trade compose

Formatted values

When format is set, onValueChange receives three fields:

FieldExampleUse for
formattedValue"12,344,444.00"What the user sees in the field
value"12344444.00"Form state / API payload (no separators)
floatValue12344444Quote math (Number.parseFloat without parsing yourself)

Store value in React state or React Hook Form and pass it back with valueIsNumericString. Use floatValue when you need a number for calculations. formattedValue is mostly for display or debugging — the component applies it to the input for you.

Examples

Cash amount

Currency prefix, clear affordance, and Max chip — with formatting enabled.

€

€4,540 available

formattedValue
—
value
—
floatValue
—

Currency row

The designed second row: the dropdown chip picks the currency and the availability sits opposite.

£
£765.00 available

£765.00 available

Limit price

Stack two amount rows in one field with a divider between the sections.

€
Limit Price
€

€4,540 available

Quantity

Units and share counts — up to four decimal places, no currency prefix.

Up to four decimal places.

Validation error

The error ring and halo come from the wrapping Field. The footer pairs the message with a recovery action.

€

React Hook Form

Store the unformatted numeric string (values.value) in form state and pass valueIsNumericString so separators are not double-applied.

form value: —

Playground

<Field> <NumberInput prefix="€" format="currency" placeholder="0.00" value={value} onValueChange={…} valueIsNumericString onClear={…}>    <InputGroupButton variant="chip" size="xs">Max</InputGroupButton> </NumberInput></Field>

Usage

import { InputGroupButton } from "@sophic/portal-ui/components/ui/input-group";
import { NumberInput } from "@sophic/portal-ui/components/ui/number-input";
import type { NumberInputChangeValues } from "@sophic/portal-ui/components/ui/number-input";

Raw entry (Houston, app-owned parsing):

<Field>
  <NumberInput
    prefix="€"
    placeholder="0.00"
    value={value}
    onChange={(e) => setValue(e.target.value)}
    onClear={() => setValue("")}
  />
</Field>

Format-as-you-type (portal trade compose):

const [values, setValues] = useState<NumberInputChangeValues>({
  value: "",
  formattedValue: "",
  floatValue: undefined,
});

<Field>
  <NumberInput
    format="currency"
    prefix="€"
    value={values.value}
    valueIsNumericString
    onValueChange={setValues}
    onClear={() => setValues({ value: "", formattedValue: "", floatValue: undefined })}
  >
    <InputGroupButton variant="chip" size="xs">Max</InputGroupButton>
  </NumberInput>
</Field>

NumberInput is the amount row only — it always lives inside a Field, which carries the card, focus ring, and error state. Trailing adornments are children.

variant="tall" is one --button-height-lg row, the same height as Input variant="tall" and Button size="lg". Drop the Field's vertical padding when you use it, so the card does not grow past that.

For a convenience wrapper, see useNumberInput in @sophic/portal-ui/lib/use-number-input.

Props

Raw mode

Omit format. Also accepts every native <input> attribute (value, onChange, placeholder, disabled, …).

Prop

Type

Default

Formatted mode

Set format to currency, quantity, or integer. Use onValueChange instead of onChange. Also accepts native <input> attributes except type and onChange.

Prop

Type

Default

onValueChange payload

Prop

Type

Default

Changelog

  • 20 August 2026 — “You might be looking for” also maps to Date Picker. Full notes
  • 19 August 2026 — “You might be looking for” map to Input and Textarea. Full notes
  • 4 August 2026 — Optional format prop merges format-as-you-type masking into Number Input (currency, quantity, integer presets). Full notes
  • 22 July 2026 — Max chip matches the currency picker pill. Full notes
  • 22 July 2026 — Invalid state colors the message only (amount stays normal). Full notes
  • 15 July 2026 — Currency chip is SelectTrigger variant="chip". Full notes
  • 15 July 2026 — Added (display-type amount row with clear affordance). Full notes

On this page