use Moneyhook
The hook takes a MoneyV2 object and returns a
default-formatted string of the amount with the correct currency indicator, along with some of the parts provided by
Intl.NumberFormat.
must be a descendent of a
component.
Anchor to useMoney-parametersParameters
- Anchor to moneymoneyMoneyV2required
Anchor to useMoney-returnsReturns
- amountstring
The localized amount, without any currency symbols or non-number types from the
parts.
- currencyCodeCurrencyCode
The currency code from the
object.
- localizedStringstring
A string returned by
for the amount and currency code, using the
locale
value in thecomponent.
- originalMoneyV2
The
object provided as an argument to the hook.
- partsNumberFormatPart[]
All parts returned by
.
- withoutTrailingZerosstring
A string with trailing zeros removed from the fractional part, if any exist. If there are no trailing zeros, then the fractional part remains. For example,
$640.00
turns into$640
.$640.42
remains$640.42
.- withoutTrailingZerosAndCurrencystring
A string without currency and without trailing zeros removed from the fractional part, if any exist. If there are no trailing zeros, then the fractional part remains. For example,
$640.00
turns into640
.$640.42
turns into640.42
.- currencyNamestring
The name for the currency code, returned by
.
- currencyNarrowSymbolstring
The currency narrow symbol returned by
.
- currencySymbolstring
The currency symbol returned by
.
UseMoneyValue
UseMoneyGeneratedType
The `useMoney` hook takes a [MoneyV2 object](https://shopify.dev/api/storefront/reference/common-objects/moneyv2) and returns a default-formatted string of the amount with the correct currency indicator, along with some of the parts provided by [Intl.NumberFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat). Uses `locale` from `ShopifyProvider`
- money
MoneyV2
UseMoneyValue
export function useMoney(money: MoneyV2): UseMoneyValue {
const {countryIsoCode, languageIsoCode} = useShop();
const locale = languageIsoCode.includes('_')
? languageIsoCode.replace('_', '-')
: `${languageIsoCode}-${countryIsoCode}`;
if (!locale) {
throw new Error(
`useMoney(): Unable to get 'locale' from 'useShop()', which means that 'locale' was not passed to '<ShopifyProvider/>'. 'locale' is required for 'useMoney()' to work`,
);
}
const amount = parseFloat(money.amount);
const {
defaultFormatter,
nameFormatter,
narrowSymbolFormatter,
withoutTrailingZerosFormatter,
withoutCurrencyFormatter,
withoutTrailingZerosOrCurrencyFormatter,
} = useMemo(() => {
const options = {
style: 'currency' as const,
currency: money.currencyCode,
};
return {
defaultFormatter: getLazyFormatter(locale, options),
nameFormatter: getLazyFormatter(locale, {
...options,
currencyDisplay: 'name',
}),
narrowSymbolFormatter: getLazyFormatter(locale, {
...options,
currencyDisplay: 'narrowSymbol',
}),
withoutTrailingZerosFormatter: getLazyFormatter(locale, {
...options,
minimumFractionDigits: 0,
maximumFractionDigits: 0,
}),
withoutCurrencyFormatter: getLazyFormatter(locale),
withoutTrailingZerosOrCurrencyFormatter: getLazyFormatter(locale, {
minimumFractionDigits: 0,
maximumFractionDigits: 0,
}),
};
}, [money.currencyCode, locale]);
const isPartCurrency = (part: Intl.NumberFormatPart): boolean =>
part.type === 'currency';
// By wrapping these properties in functions, we only
// create formatters if they are going to be used.
const lazyFormatters = useMemo(
() => ({
original: (): MoneyV2 => money,
currencyCode: (): CurrencyCode => money.currencyCode,
localizedString: (): string => defaultFormatter().format(amount),
parts: (): Intl.NumberFormatPart[] =>
defaultFormatter().formatToParts(amount),
withoutTrailingZeros: (): string =>
amount % 1 === 0
? withoutTrailingZerosFormatter().format(amount)
: defaultFormatter().format(amount),
withoutTrailingZerosAndCurrency: (): string =>
amount % 1 === 0
? withoutTrailingZerosOrCurrencyFormatter().format(amount)
: withoutCurrencyFormatter().format(amount),
currencyName: (): string =>
nameFormatter().formatToParts(amount).find(isPartCurrency)?.value ??
money.currencyCode, // e.g. "US dollars"
currencySymbol: (): string =>
defaultFormatter().formatToParts(amount).find(isPartCurrency)?.value ??
money.currencyCode, // e.g. "USD"
currencyNarrowSymbol: (): string =>
narrowSymbolFormatter().formatToParts(amount).find(isPartCurrency)
?.value ?? '', // e.g. "$"
amount: (): string =>
defaultFormatter()
.formatToParts(amount)
.filter((part) =>
['decimal', 'fraction', 'group', 'integer', 'literal'].includes(
part.type,
),
)
.map((part) => part.value)
.join(''),
}),
[
money,
amount,
nameFormatter,
defaultFormatter,
narrowSymbolFormatter,
withoutCurrencyFormatter,
withoutTrailingZerosFormatter,
withoutTrailingZerosOrCurrencyFormatter,
],
);
// Call functions automatically when the properties are accessed
// to keep these functions as an implementation detail.
return useMemo(
() =>
new Proxy(lazyFormatters as unknown as UseMoneyValue, {
// eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
get: (target, key) => Reflect.get(target, key)?.call(null),
}),
[lazyFormatters],
);
}
UseMoneyValue
- amount
The localized amount, without any currency symbols or non-number types from the `Intl.NumberFormat.formatToParts` parts.
string
- currencyCode
The currency code from the `MoneyV2` object.
CurrencyCode
- currencyName
The name for the currency code, returned by `Intl.NumberFormat`.
string
- currencyNarrowSymbol
The currency narrow symbol returned by `Intl.NumberFormat`.
string
- currencySymbol
The currency symbol returned by `Intl.NumberFormat`.
string
- localizedString
A string returned by `new Intl.NumberFormat` for the amount and currency code, using the `locale` value in the [`LocalizationProvider` component](https://shopify.dev/api/hydrogen/components/localization/localizationprovider).
string
- original
The `MoneyV2` object provided as an argument to the hook.
MoneyV2
- parts
All parts returned by `Intl.NumberFormat.formatToParts`.
NumberFormatPart[]
- withoutTrailingZeros
A string with trailing zeros removed from the fractional part, if any exist. If there are no trailing zeros, then the fractional part remains. For example, `$640.00` turns into `$640`. `$640.42` remains `$640.42`.
string
- withoutTrailingZerosAndCurrency
A string without currency and without trailing zeros removed from the fractional part, if any exist. If there are no trailing zeros, then the fractional part remains. For example, `$640.00` turns into `640`. `$640.42` turns into `640.42`.
string
{
/**
* The currency code from the `MoneyV2` object.
*/
currencyCode: CurrencyCode;
/**
* The name for the currency code, returned by `Intl.NumberFormat`.
*/
currencyName?: string;
/**
* The currency symbol returned by `Intl.NumberFormat`.
*/
currencySymbol?: string;
/**
* The currency narrow symbol returned by `Intl.NumberFormat`.
*/
currencyNarrowSymbol?: string;
/**
* The localized amount, without any currency symbols or non-number types from the `Intl.NumberFormat.formatToParts` parts.
*/
amount: string;
/**
* All parts returned by `Intl.NumberFormat.formatToParts`.
*/
parts: Intl.NumberFormatPart[];
/**
* A string returned by `new Intl.NumberFormat` for the amount and currency code,
* using the `locale` value in the [`LocalizationProvider` component](https://shopify.dev/api/hydrogen/components/localization/localizationprovider).
*/
localizedString: string;
/**
* The `MoneyV2` object provided as an argument to the hook.
*/
original: MoneyV2;
/**
* A string with trailing zeros removed from the fractional part, if any exist. If there are no trailing zeros, then the fractional part remains.
* For example, `$640.00` turns into `$640`.
* `$640.42` remains `$640.42`.
*/
withoutTrailingZeros: string;
/**
* A string without currency and without trailing zeros removed from the fractional part, if any exist. If there are no trailing zeros, then the fractional part remains.
* For example, `$640.00` turns into `640`.
* `$640.42` turns into `640.42`.
*/
withoutTrailingZerosAndCurrency: string;
}
Example code
examples
Example code
description
I am the default example
JavaScript
import {useMoney, ShopifyProvider} from '@shopify/hydrogen-react'; export function App() { return ( <ShopifyProvider languageIsoCode="EN" countryIsoCode="US"> <UsingMoney /> </ShopifyProvider> ); } function UsingMoney() { const myMoney = {amount: '100', currencyCode: 'USD'}; const money = useMoney(myMoney); return ( <> <div>Localized money: {money.localizedString}</div> <div>Money without trailing zeros: {money.withoutTrailingZeros}</div> </> ); }
TypeScript
import {useMoney, ShopifyProvider} from '@shopify/hydrogen-react'; import type {MoneyV2} from '@shopify/hydrogen-react/storefront-api-types'; export function App() { return ( // @ts-expect-error intentionally missing the rest of the props <ShopifyProvider countryIsoCode="US" languageIsoCode="EN"> <UsingMoney /> </ShopifyProvider> ); } function UsingMoney() { const myMoney = {amount: '100', currencyCode: 'USD'} satisfies MoneyV2; const money = useMoney(myMoney); return ( <> <div>Localized money: {money.localizedString}</div> <div>Money without trailing zeros: {money.withoutTrailingZeros}</div> </> ); }