# Money

> The core primitive. A monetary value, formatted correctly.

Source: https://lopifi.com/components/money
Part of: Lopifi — US GAAP books on autopilot, reviewed by a CPA (https://lopifi.com)

---

- **Family:** Primitives — The layer everything else composes. Build these first; nothing above them is right until they are.
- **Status:** Implemented
- **Spec:** https://lopifi.com/docs/catalog/01-primitives

## Install

```bash
npx shadcn@latest add @lopifi/theme
npx shadcn@latest add @lopifi/money
```

## Specification

> The core primitive. Every monetary value in the system renders through it.

```tsx
<Money value={{ amount: 124056, currency: "USD" }} />        // $1,240.56
<Money value={{ amount: -124056, currency: "USD" }} accounting />  // ($1,240.56)
<Money value={null} />                                        // n/a
<Money value={{ amount: 0, currency: "USD" }} statement />    // —
```

```ts
interface MoneyProps extends React.ComponentPropsWithoutRef<"span"> {
  value: MoneyValue | null;
  /** parentheses for negatives (statements/tables) vs. a leading − (deltas) */
  accounting?: boolean;
  /** em dash for a true zero — statements only */
  statement?: boolean;
  size?: "xs" | "sm" | "md" | "lg" | "hero";
  /** subordinate the symbol; default true */
  showSymbol?: boolean;
  /** show the ISO code — required in mixed-currency contexts */
  showCode?: boolean;
  /** mark as converted: renders "≈" and requires a rate for the tooltip */
  approximate?: { rate: number; asOf: Date; from: string };
  redacted?: boolean;
  locale?: string;
}
```

**Layer 3 — structure:** `[≈] [symbol] [integer] [.decimals] [code]` — five slots, four optional. The paren column is reserved on both sides regardless of sign.

**Layer 4 — type:** one size, one weight. `tnum` + `case` always. Symbol and code at `--text-tertiary`; decimals at `--text-tertiary` only at `lg`/`hero`.

**Motion:** none, except the [value flash](../motion/03-catalog.md#value-flash) when `live` and the [crossfade](../motion/03-catalog.md) when the value changes from a user action. **Never interpolates.**

**Edge cases:** JPY 0dp · KWD 3dp · `bigint` amounts · negative zero (renders as zero) · the widest-plausible-value width reservation · `aria-label` announcing the sign in words.

**Why it matters:** if this is wrong, everything is wrong. It also carries the whole `case`/`tnum`/paren-alignment craft that the rest of the library assumes.

## Rules this component obeys

Money is minor units, never floats. `null` is not `0` and neither is redacted. Negatives render in accounting parentheses with the parenthesis column reserved on both sides. Debit and credit are two columns. Per-currency decimal places. Polarity is explicit — up is not always good. Every figure states its period, entity, currency, basis and as-of.
