Staaarter

Billing Multi Currency Invoice Preview

An invoice line-item preview with a currency pill-toggle in the header. Every line item, the subtotal, tax, and total are stored once in USD and converted live when a different currency is selected, formatted with Intl.NumberFormat so symbols and decimal rules match the chosen locale. Built for billing portals that serve customers who bill in a currency other than the platform's base currency.

By Staaarter Team
Billing
Updated May 20, 2026
Docs
Live preview

Docs

Installation

A real shadcn registry command, not a copy-paste stand-in: it fetches this block plus its button dependencies and any missing npm packages, and installs them straight into your project.

npx shadcn add https://staaarter.com/r/billing-multi-currency-invoice-preview.json

Prefer not to use the CLI? Copy the source from the Code toggle above into src/components/blocks/billing/billing75.tsx instead.

Usage

The file also exports billing75Demo, the exact props behind the preview above. Spread it to get a working section in one line, then replace it with your own data.

import { Billing75, billing75Demo } from "@/components/blocks/billing/billing75";

export default function Page() {
  return <Billing75 {...billing75Demo} />;
}

Props

PropTypeDefaultDescription
titlestring"Invoice preview"Heading shown in the card header.
invoiceNumberstringnoneOptional invoice number or reference shown under the title.
lineItemsInvoiceLineItemUsd[]noneLine items with amounts stored in USD; each is converted to the active currency for display.
taxRatePercentnumber0Tax rate applied to the USD subtotal; the tax row only renders when this is greater than 0.
currenciesInvoiceCurrency[]noneCurrencies rendered as toggle pills, each with a rate applied to convert from USD.
defaultCurrencyCodestringcurrencies[0].codeWhich currency is active on first render.
downloadHrefstring"#"Href for the Download PDF link.
classNamestringnoneExtra classes for the outer container.

Types

interface InvoiceCurrency {
  code: string;
  symbol: string;
  rate: number;
}

interface InvoiceLineItemUsd {
  description: string;
  quantity?: number;
  amountUsd: number;
}

Behavior notes

  • The active currency is local component state; every amount on screen (line items, subtotal, tax, total) is recalculated from the USD source values whenever the toggle changes, with no page reload.
  • Amounts are formatted with Intl.NumberFormat's currency style using the active currency's ISO code, so symbol placement and decimal precision follow that locale's convention automatically, not a hardcoded prefix.
  • The tax row only renders when taxRatePercent is greater than 0, so invoices with no tax collapse to a two-line subtotal/total breakdown.
  • The Download PDF link is a next/link with the current downloadHref, it doesn't itself regenerate a PDF in the selected currency, that's left to your backend.
  • If a currency code you pass isn't a valid ISO 4217 code, Intl.NumberFormat throws; the component catches that and falls back to a plain two-decimal number for that currency.

Frequently asked questions