How to format currency amounts in TanStack Start v1
Display prices with currency symbols and separators
Problem
Prices combine two localization challenges: currency representation and number formatting. The same monetary value appears as $1,200.50 in the United States and 1 200,50 € in Germany. The currency symbol moves, the decimal and grouping separators swap, and even the spacing changes.
These conventions are not preferences but expectations. Displaying prices in an unfamiliar format makes users question whether they are seeing the correct amount. A price shown as "1200.50 EUR" to a German user or "1.200,50$" to a US user creates friction and erodes trust.
Solution
Format monetary values based on both the currency and the user's locale. This combines currency symbol placement with locale-specific number formatting rules, creating prices that match regional expectations for how money should look.
Use react-intl's formatNumber method with the style: 'currency' option to apply both the currency code and the user's locale formatting conventions. The browser's Intl.NumberFormat API handles symbol placement, separator choice, and spacing automatically.
Steps
1. Create a currency formatting component
Build a reusable component that accepts a numeric value and a currency code, then formats the price using the user's locale.
import { useIntl } from "react-intl";
interface PriceProps {
value: number;
currency: string;
}
export function Price({ value, currency }: PriceProps) {
const intl = useIntl();
const formattedPrice = intl.formatNumber(value, {
style: "currency",
currency: currency,
});
return <span>{formattedPrice}</span>;
}
The useIntl hook provides access to the formatting API. The formatNumber method with style: 'currency' applies both the currency symbol and locale-specific number formatting.
2. Use the component with different currencies
Display prices throughout your application by passing the numeric amount and currency code.
export default function ProductCard() {
return (
<div>
<h2>Premium Plan</h2>
<Price value={1200.5} currency="USD" />
</div>
);
}
The component automatically formats the price according to the user's locale. A US user sees "$1,200.50" while a German user sees "1.200,50 $".
3. Format prices with custom decimal precision
Control the number of decimal places displayed by adding minimumFractionDigits and maximumFractionDigits options.
export function PriceWithPrecision({ value, currency }: PriceProps) {
const intl = useIntl();
const formattedPrice = intl.formatNumber(value, {
style: "currency",
currency: currency,
minimumFractionDigits: 2,
maximumFractionDigits: 2,
});
return <span>{formattedPrice}</span>;
}
This ensures consistent decimal display across all prices, even when the value is a whole number like 100.
4. Create a helper for inline formatting
For cases where a component wrapper is unnecessary, create a formatting helper function.
import { useIntl } from "react-intl";
export function useFormatCurrency() {
const intl = useIntl();
return (value: number, currency: string) => {
return intl.formatNumber(value, {
style: "currency",
currency: currency,
});
};
}
Use this hook when you need formatted prices in attributes, computed values, or other non-JSX contexts.
export function CheckoutSummary({ total }: { total: number }) {
const formatCurrency = useFormatCurrency();
return (
<button aria-label={`Pay ${formatCurrency(total, "USD")}`}>Checkout</button>
);
}
The helper returns a plain string suitable for any context where JSX components cannot be used.