# useMoney
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).
```jsx
import {useMoney, ShopifyProvider} from '@shopify/hydrogen';
export function App() {
return (
);
}
function UsingMoney() {
const myMoney = {amount: '100', currencyCode: 'USD'};
const money = useMoney(myMoney);
return (
<>
Localized money: {money.localizedString}
Money without trailing zeros: {money.withoutTrailingZeros}
>
);
}
```
```tsx
import {useMoney, ShopifyProvider} from '@shopify/hydrogen';
import type {MoneyV2} from '@shopify/hydrogen/storefront-api-types';
export function App() {
return (
// @ts-expect-error intentionally missing the rest of the props
);
}
function UsingMoney() {
const myMoney = {amount: '100', currencyCode: 'USD'} satisfies MoneyV2;
const money = useMoney(myMoney);
return (
<>
Localized money: {money.localizedString}
Money without trailing zeros: {money.withoutTrailingZeros}
>
);
}
```
## Props
`useMoney` must be a descendent of a `ShopifyProvider` component.
### UseMoneyGeneratedType
#### Returns: UseMoneyValue
#### Params:
- money: MoneyV2
export function useMoney(money: MoneyV2): UseMoneyValue {
const {countryIsoCode, languageIsoCode} = useShop();
const locale = `${languageIsoCode}-${countryIsoCode}`;
if (!locale) {
throw new Error(
`useMoney(): Unable to get 'locale' from 'useShop()', which means that 'locale' was not passed to ''. 'locale' is required for 'useMoney()' to work`,
);
}
const amount = parseFloat(money.amount);
const options = useMemo(
() => ({
style: 'currency',
currency: money.currencyCode,
}),
[money.currencyCode],
);
const defaultFormatter = useLazyFormatter(locale, options);
const nameFormatter = useLazyFormatter(locale, {
...options,
currencyDisplay: 'name',
});
const narrowSymbolFormatter = useLazyFormatter(locale, {
...options,
currencyDisplay: 'narrowSymbol',
});
const withoutTrailingZerosFormatter = useLazyFormatter(locale, {
...options,
minimumFractionDigits: 0,
maximumFractionDigits: 0,
});
const withoutCurrencyFormatter = useLazyFormatter(locale);
const withoutTrailingZerosOrCurrencyFormatter = useLazyFormatter(locale, {
minimumFractionDigits: 0,
maximumFractionDigits: 0,
});
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: () => money,
currencyCode: () => money.currencyCode,
localizedString: () => defaultFormatter().format(amount),
parts: () => defaultFormatter().formatToParts(amount),
withoutTrailingZeros: () =>
amount % 1 === 0
? withoutTrailingZerosFormatter().format(amount)
: defaultFormatter().format(amount),
withoutTrailingZerosAndCurrency: () =>
amount % 1 === 0
? withoutTrailingZerosOrCurrencyFormatter().format(amount)
: withoutCurrencyFormatter().format(amount),
currencyName: () =>
nameFormatter().formatToParts(amount).find(isPartCurrency)?.value ??
money.currencyCode, // e.g. "US dollars"
currencySymbol: () =>
defaultFormatter().formatToParts(amount).find(isPartCurrency)?.value ??
money.currencyCode, // e.g. "USD"
currencyNarrowSymbol: () =>
narrowSymbolFormatter().formatToParts(amount).find(isPartCurrency)
?.value ?? '', // e.g. "$"
amount: () =>
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
### currencyCode
value: `CurrencyCode`
The currency code from the `MoneyV2` object.
### currencyName
value: `string`
The name for the currency code, returned by `Intl.NumberFormat`.
### currencySymbol
value: `string`
The currency symbol returned by `Intl.NumberFormat`.
### currencyNarrowSymbol
value: `string`
The currency narrow symbol returned by `Intl.NumberFormat`.
### amount
value: `string`
The localized amount, without any currency symbols or non-number types from the `Intl.NumberFormat.formatToParts` parts.
### parts
value: `NumberFormatPart[]`
All parts returned by `Intl.NumberFormat.formatToParts`.
### localizedString
value: `string`
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).
### original
value: `MoneyV2`
The `MoneyV2` object provided as an argument to the hook.
### withoutTrailingZeros
value: `string`
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`.
### withoutTrailingZerosAndCurrency
value: `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`.
## Related
- [Money](/api/hydrogen/components/money)