Skip to content

Components · Billing

Money

An amount of one currency, formatted by Intl.NumberFormat in tabular figures.

@rookcom/monarch-reactComponent

Locales and minor units

$1,299.001.299,00 €₹1,29,900.00¥4,500

Usage examples

Compact, signs and negatives

Purpose

Displays a monetary amount the same way everywhere: localised, in its own currency, from minor units without floating-point loss, with an accessible full value when shortened.

Use when

  • Prices, invoice lines, payroll figures, renewal costs and balances.
  • Amounts stored as integer minor units (cents, paise) next to an ISO 4217 currency code.

Avoid when

  • Entering an amount: use a currency input.
  • Adding amounts in different currencies: list them per currency instead; Money never converts.

Design principles

  • One amount, one currency. Conversion and summing across currencies stay in the product.
  • Tabular figures and no wrapping, so columns of amounts line up.
  • The sign carries the meaning; colour (toneNegative) only reinforces it.
  • Shortened amounts never hide the real value: compact notation keeps the full amount for screen readers and as a hover title.

API reference

import { Money, currencyDigits, formatMoney } from '@rookcom/monarch-react';
ExportKindRenderingRoot class
Moneycomponentserver-safe.mn-money
currencyDigitsutilityserver-safe–
formatMoneyutilityserver-safe–

The ref and native attributes go to the root <span>.

formatMoney(amount, currency, options) returns the same string for exports, charts and aria-labels; currencyDigits(code) gives the minor-unit digits (USD 2, JPY 0, KWD 3).

Decimal strings ("1234.50") and bigints are formatted exactly; they need a runtime with Intl.NumberFormat v3 (all current evergreen browsers and Node 20+).

Generated from the TypeScript declarations of packages/react/src/components/billing/money.

Properties

With minorUnits, amount must be an integer; a fractional string throws a RangeError.

Money

A formatted amount in tabular figures. With `notation="compact"` the short form is shown and the full amount is given to assistive technology and as a hover title.

PropTypeDescription
amount requiredMoneyAmount | nullThe amount. `null` or `undefined` renders `emptyLabel`.
currency requiredstringISO 4217 code, e.g. `USD`, `EUR`, `INR`.
classNamestring
currencyDisplay"symbol" | "name" | "code" | "narrowSymbol"How the currency is written: `symbol` ($), `narrowSymbol`, `code` (USD) or `name` (US dollars). Default `symbol`.
currencySign"standard" | "accounting"`accounting` writes negatives in parentheses where the locale does. Default `standard`.
emptyLabelstringShown when `amount` is missing. Default "—", read as "No amount".
idstring
localestringBCP 47 locale, e.g. `en-IN`. Default: the runtime locale.
maximumFractionDigitsnumber
minimumFractionDigitsnumber
minorUnitsboolean`amount` is in the currency's minor units (cents, paise): `1999` with USD is $19.99.
notation"compact" | "standard"`compact` writes $1.2M. Default `standard`.
signDisplay"auto" | "always" | "exceptZero" | "never"`Intl.NumberFormat` sign display. `exceptZero` shows +/− for gains and losses. Default `auto`.
toneNegativebooleanColour negative amounts with the danger text colour (`data-negative` is set either way). The minus sign or parentheses always carry the meaning. Default `false`.

Variants

PropValuesDescription
notation'standard''compact'compact writes $1.3M and adds the full value for assistive technology (data-notation).
signDisplay'auto''always''exceptZero''never'exceptZero writes +$42.00 for gains.
currencyDisplay'symbol''narrowSymbol''code''name'$, $, USD or “US dollars”.
currencySign'standard''accounting'accounting writes negatives in parentheses where the locale does.

States

StateExposed asBehaviour
Negativedata-negativeAlways set for amounts below zero; toneNegative adds data-tone="danger".
Emptydata-emptyamount null or undefined: an em dash read as “No amount”, or emptyLabel.
Compactdata-notation="compact"Short visible text, full amount in visually hidden text and title.

Interaction behaviour

  • None. In compact notation the native title shows the full amount on hover; screen readers read the full amount directly.

Keyboard support

Not interactive, so there is no keyboard behaviour.

Accessibility

Role
none (inline text)
Accessible name
The formatted amount is the text itself.
  • Compact amounts render the short form aria-hidden and the full form in visually hidden text, so “$1.3M” is read as “$1,250,000.00”.
  • The empty dash is hidden from screen readers and replaced by “No amount”.
  • Negative colour is never the only cue: the minus sign or parentheses are always present.

Responsive behaviour

  • Amounts never wrap (white-space: nowrap). Use notation="compact" where a column is narrow on phones.

Theme support

  • Inherits the surrounding text colour; toneNegative uses --mn-color-danger-strong, which meets AA in every theme.
  • The empty state uses --mn-color-text-muted.

Do and don't

Do

  • Store and pass integer minor units with minorUnits; it avoids floating-point rounding.
  • Pass the viewer’s locale so separators and symbol placement match their region.
  • Show one line per currency when totals span currencies.

Don't

  • Do not add amounts of different currencies together before displaying them.
  • Do not rely on red alone to show a negative amount.
  • Do not shorten amounts with compact where the exact figure is the point, such as an invoice total.

Dependencies

KindDepends on
npm packagesreact
Monarch componentsVisuallyHidden

Testing coverage

  • Formats in en-US, de-DE and en-IN.
  • Minor units use the currency’s digits (USD, JPY, KWD), including small and negative values.
  • Bigint and decimal-string amounts keep full precision; fractional minor units throw.
  • Compact notation, sign display, accounting sign and currency display.
  • Compact amounts expose the full value to assistive technology and as a title, without duplicating equal text.
  • Negative marking and opt-in danger tone; empty state and emptyLabel.
  • Forwards the ref and keeps a consumer title.
CheckCovered
Axe in jsdomYes
Server renderingYes
Browser suitesVisual baselines: /__gallery; Cross-browser axe: /components/money

Tests: packages/react/src/components/billing/money