Skip to content

Money input component

components specs/components/money-input.kmd

A currency-aware amount field — optional currency selector, per-currency decimal precision, locale-grouped formatting on blur, robust parsing of what the user types, and a minor-unit storage contract. Pairs the money display mask (data/masks.kmd) with input behavior. Modeled after Polaris (price fields). Used by Koder Exchange, Invest, Billing, marketplace, checkout.

When this spec applies

Primary triggers

All triggers

Specification body

Component — Money input

Status: v0.1.0 — Draft. Promoted from the Shopify Polaris parity scan (meta/docs/stack #091). Source: https://polaris.shopify.com/components/selection-and-input/text-field (price/currency usage). Display mask: specs/data/masks.kmd.

R1 — Currency

  • The field has an associated currency. Either fixed (shown as a prefix/suffix affix, e.g. R$) or selectable via an adjacent currency selector when the surface supports multiple currencies.
  • Changing the selected currency re-applies that currency's precision (R2) and symbol; it never silently rescales the entered numeric amount.

R2 — Precision per currency

  • Decimal places follow the currency, not the locale: BRL/USD/EUR = 2, JPY/CLP = 0, BHD/KWD = 3. Use the ISO-4217 minor-unit exponent, not a hardcoded 2.
  • On blur, the value is rounded to that precision (half-up); the input shows the formatted amount.

R3 — Formatting & parsing

  • Display (on blur / read): grouped per the UI locale (specs/data/masks.kmd money mask) with the currency affix.
  • Parsing (what the user types): accept the locale's decimal + grouping separators, an optional leading sign, and a pasted formatted string; reject letters/extra symbols. Be liberal in, strict out.
  • inputmode="decimal"; never numeric (decimals needed).

R4 — Storage contract

  • Persist as an integer in the currency's minor units (cents) + the currency code — never a float (no binary-float money), aligned with specs/data/field-types.kmd. Display is derived from this pair.

R5 — Range & validation

  • Optional min/max + non-negative constraints; violations show an inline message (specs/errors/user-facing-messages.kmd), never silent clamp.
  • Empty vs zero are distinct (empty = unset).

R6 — Accessibility & i18n

  • Real <label>; the currency affix/selector is part of the accessible name ("Amount in Brazilian Real").
  • Right-alignment is presentational only; the value reads correctly to AT.
  • All formatting/parsing is locale + currency aware (specs/i18n/contract.kmd); the stored minor-unit value is locale-invariant.

Não-escopo

  • FX conversion between currencies (a service concern).
  • The money display mask mechanics (specs/data/masks.kmd).
  • Accounting/rounding policy beyond per-currency precision (domain rules).

References