Money & Numbers

Show amounts of money, percentages, quantities and units the same way everywhere in your app.

Invoice total: $1,250,000.50

Refund: -$42.90

Revenue: $1,290,000.00

Conversion: 12%

Weight: 12.5 kg

import { Money } from "@hel/ui/money"
import { NumberText } from "@hel/ui/number-text"
import { Stack } from "@hel/ui/stack"

When to use it

Use Money for every amount of money and NumberText for every other number that people read: a count, a percentage, a weight, a change from last week. They read one setting for the language, digits and currency, so a price in a table, in a dialog and in a chart label look the same, and change together.

Do not build amounts with toFixed or toLocaleString in each place. The commas, decimals and currency symbols drift apart, and a new language means finding every one of them. To let people type an amount, use a Number Field or the amount mask.

Import

import { Money } from "@hel/ui/money"
import { NumberText } from "@hel/ui/number-text"

Usage

Both are pieces of Text, so they take size, weight and the rest, and they can sit inside a sentence.

<Money amount="1250000.50" />
<Money amount={123456} amountIn="minor" currency="USD" />
<NumberText value={0.1245} format="percent" />
<NumberText value={12.5} format="unit" unit="kilogram" />

An amount can be a number, a BigInt or a decimal string. Pass amounts from your API as the strings they come in, because a string keeps every digit and a number can lose some. The element is a <data> tag with the exact value, and a missing or invalid value shows a dash, or the emptyText you give.

Examples

Currencies and styles

The currency comes from the config of the app, and currency changes it for one amount. locale changes the language of one amount, amountIn="minor" reads an amount given in cents, and currencyDisplay writes the code or the name instead of the symbol. currencySign="accounting" writes a negative amount in parentheses, in the languages that do that.

US dollars

$1,234.50

Euros, in German

1.234,50 €

Iraqi dinars

IQD 1,250,000

From cents

$1,234.56

Currency code

USD 1,234.50

Accounting

($1,234.50)
import { Flex } from "@hel/ui/flex"
import { Money } from "@hel/ui/money"
import { Stack } from "@hel/ui/stack"

Iraqi dinars are a case to watch: the browser writes IQD with no decimals, but the currency has three digits (fils). If your backend sends fils, pass minorUnits={3}, or set it once for the currency in money.currencies in the config.

Gains and losses

Numbers are plain text by default. tones gives the positive, negative and zero amounts a color, and signDisplay="exceptZero" adds the plus sign, which is what you want for a change. variant="contained" draws the number in a small tinted pill.

Subscriptions

+$1,840.00+8.2%

One-time sales

-$620.00-3.4%

Refunds

$0.000%
import { Flex } from "@hel/ui/flex"
import { Money } from "@hel/ui/money"
import { NumberText } from "@hel/ui/number-text"

The tones are neutral, positive, negative and caution, and the theme decides the colors. Color alone should never carry the meaning, so keep the sign or a word next to it. Set the tones once in the config to color every amount in the app, and use tone to force one for a single amount.

Short form

compact writes $1,290,000 as "$1.2M". It cuts off the extra digits and does not round them up, so the short form never shows more than the real amount. Use compact="auto" with compactOptions.from to shorten only the large ones. On hover the full amount appears, and a screen reader reads the full amount too, never the short one.

Full

$1,290,000.00

Short

$1,290,000.00

Long words

1,290,000

Only from 10,000 up

9,50048,200

Hover a short amount to see the full one.

import { Flex } from "@hel/ui/flex"
import { Money } from "@hel/ui/money"
import { NumberText } from "@hel/ui/number-text"

Props

Money

PropTypeDefault
amounta number, a BigInt or a decimal stringrequired
currencyan ISO 4217 codefrom the config, "USD"
amountIn"major" | "minor""major"
minorUnitsnumberthe digits of the currency
symbolstringthe symbol of the currency
currencyDisplay"symbol" | "narrowSymbol" | "code" | "name""symbol"
currencySign"standard" | "accounting""standard"

NumberText

PropTypeDefault
valuea number, a BigInt or a decimal stringrequired
format"decimal" | "percent" | "unit""decimal"
percentOf"fraction" | "hundred""fraction"
unita unit such as "kilogram"none
unitDisplay"short" | "narrow" | "long""short"

With percentOf="fraction", 0.125 is 12.5%. If your API sends 12.5 for 12.5%, use percentOf="hundred".

Shared by both

PropTypeDefault
locale / numberingSystema BCP 47 locale, a digits namefrom the config
compactboolean | "auto"from the config
compactOptions{ from, display, fractionDigits, roundingMode }from the config
minimumFractionDigits / maximumFractionDigitsnumberfrom the currency or the locale
roundingModean Intl rounding modethe browser's
trailingZeroDisplay"auto" | "stripIfInteger""auto"
signDisplay"auto" | "always" | "exceptZero" | "negative" | "never""auto"
tone / tonesa tone, or a tone for each signneutral
variant"plain" | "contained""plain"
renderParts(parts, result) => ReactNodenone
showFullOnHoverbooleantrue
emptyTextReactNodea dash