f-ui
Components

Currency Format

Pure money helpers for parse, display, edit strings, and ISO 4217 currency metadata — no UI dependencies.

Currency Format ships parseMoneyNumber, formatMoneyForDisplay, formatMoneyForEdit, listCurrencies, getCurrencyMeta, and searchCurrencies. No npm dependencies. Use in tables, summaries, or custom read-only UI. For the money field component, see Currency Input.

Installing

pnpm dlx shadcn@latest add https://ui.isaacfei.com/r/currency-format.json
npx shadcn@latest add https://ui.isaacfei.com/r/currency-format.json
yarn dlx shadcn@latest add https://ui.isaacfei.com/r/currency-format.json
bun x shadcn@latest add https://ui.isaacfei.com/r/currency-format.json

With a namespace: npx shadcn@latest add @f-ui/currency-format.

Usage

import {
  formatMoneyForDisplay,
  formatMoneyForEdit,
  getCurrencyMeta,
  listCurrencies,
  parseMoneyNumber,
  searchCurrencies,
} from '@/components/f-ui/currency-format/currency-format';

Examples

Default measure code

USD 1,234.56

Measure none (Currency sibling)

1,234.56

Measure symbol (opt-in)

$1,234.56

Decimal style (no code)

42.50

ISO list — listCurrencies() length

162

Search — searchCurrencies("eur") (first 5)

EUR

Empty parse — helpers return null / display "-"; in tables you often pair with EmptyValuePlaceholder instead

parseMoneyNumber(""):null

Placeholder:

"use client";

import {
  formatMoneyForDisplay,
  listCurrencies,
  parseMoneyNumber,
  searchCurrencies,
} from "@/components/f-ui/currency-format/currency-format";
import { EmptyValuePlaceholder } from "@/components/f-ui/empty-value-placeholder";

export function CurrencyFormatDemo() {
  const withCode = formatMoneyForDisplay(1234.56, "USD", "en-US");
  const none = formatMoneyForDisplay(1234.56, "USD", "en-US", {
    measure: "none",
  });
  const symbol = formatMoneyForDisplay(1234.56, "USD", "en-US", {
    measure: "symbol",
  });
  const plain = formatMoneyForDisplay(42.5, undefined, "en-US");
  const emptyParse = parseMoneyNumber("");
  const currencyCount = listCurrencies().length;
  const eurMatches = searchCurrencies("eur", "en-US").slice(0, 5);

  return (
    <div className="max-w-md space-y-4 text-sm">
      <div className="space-y-1">
        <p className="text-muted-foreground text-xs">
          Default measure <code className="text-foreground">code</code>
        </p>
        <p className="font-mono tabular-nums">{withCode}</p>
      </div>
      <div className="space-y-1">
        <p className="text-muted-foreground text-xs">
          Measure <code className="text-foreground">none</code> (Currency sibling)
        </p>
        <p className="font-mono tabular-nums">{none}</p>
      </div>
      <div className="space-y-1">
        <p className="text-muted-foreground text-xs">
          Measure <code className="text-foreground">symbol</code> (opt-in)
        </p>
        <p className="font-mono tabular-nums">{symbol}</p>
      </div>
      <div className="space-y-1">
        <p className="text-muted-foreground text-xs">Decimal style (no code)</p>
        <p className="font-mono tabular-nums">{plain}</p>
      </div>
      <div className="space-y-1">
        <p className="text-muted-foreground text-xs">
          ISO list — <code className="text-foreground">listCurrencies()</code> length
        </p>
        <p className="font-mono tabular-nums">{currencyCount}</p>
      </div>
      <div className="space-y-1">
        <p className="text-muted-foreground text-xs">
          Search — <code className="text-foreground">searchCurrencies(&quot;eur&quot;)</code>{" "}
          (first 5)
        </p>
        <p className="font-mono tabular-nums">{eurMatches.join(", ")}</p>
      </div>
      <div className="space-y-1">
        <p className="text-muted-foreground text-xs">
          Empty parse — helpers return null / display &quot;-&quot;; in tables you often pair
          with <code className="text-foreground">EmptyValuePlaceholder</code> instead
        </p>
        <p className="flex flex-wrap items-center gap-2">
          <span className="text-muted-foreground">parseMoneyNumber(&quot;&quot;):</span>
          <span className="font-mono">{emptyParse === null ? "null" : String(emptyParse)}</span>
        </p>
        <p className="flex flex-wrap items-center gap-2">
          <span className="text-muted-foreground">Placeholder:</span>
          <EmptyValuePlaceholder />
        </p>
      </div>
    </div>
  );
}

API Reference

ExportRole
parseMoneyNumber(value)Returns a finite number or null; accepts numbers, bigints, or strings with grouping / locale-style separators.
formatMoneyForDisplay(value, currencyCode?, locale?, options?)Formatted amount string, or "-" when the value cannot be parsed. Uses per-currency fraction digits (e.g. JPY → 0). Fourth arg is FormatMoneyOptions (measure).
formatMoneyForEdit(value, currencyCode?, locale?)Ungrouped decimal string for focus/edit — no symbol. Empty when value is null.
listCurrencies()All ISO 4217 codes via Intl.supportedValuesOf('currency'), with a static fallback for older runtimes.
getCurrencyMeta(code, locale?){ code, symbol, minFractionDigits, maxFractionDigits } for a locale.
searchCurrencies(query, locale?, allowed?)Filter codes by case-insensitive code or symbol match.

measure Options

When currencyCode is provided, options.measure controls how currency is shown (helper default code). Table / list / editable cells via f.currency omit the code unless measure is set — the column header is the sibling.

measureExample (USD, en-US)When
"none"1,204.00Visible Currency sibling on the same surface; table cell default
"code"USD 1,204.00Lone amount / KPI / prose / Descriptions (helper default)
"symbol"$1,204.00Consumer / marketing demos only (opt-in)

When currencyCode is omitted, the helper keeps a plain decimal path (no measure prefix).

On this page