useNumberFormat
Provider-agnostic number formatting context for Docyrus UI components. Mirror of useDateFormat — wired automatically by DocyrusTenantProvider, but works with any number formatting library.
Installation
pnpm dlx @docyrus/cli add @docyrus/hooks-use-number-formatThe module exports useNumberFormat() (hook) and <NumberFormatProvider> (provider). It has zero runtime dependencies — the formatter itself is supplied by you (or by a parent <DocyrusTenantProvider>).
Overview
useNumberFormat() is the read side of a small provider-agnostic context. Components inside the tree call it to get a formatNumber(value, options?) function; the provider above the tree decides how the formatting actually happens.
- No provider mounted → the hook returns a built-in sentinel that renders
String(value). Data-grid / data-table hooks detect this and skip injecting the formatter so the cell's own locale-aware fallback (Intl.NumberFormatfor currency / percent) still runs. <DocyrusTenantProvider>mounted → the provider installs aformatNumberbacked by the tenant'snumberUtils(from@docyrus/app-utils), so every cell / chart axis / value renderer respects the tenant'sdecimalSeparator,thousandSeparator,decimalPrecision, andlocalesettings.- Custom provider mounted → you decide. Wrap any library (Intl, dinero.js, your own helper) with
<NumberFormatProvider>and components inside the tree pick it up the same way.
Usage
Consume in a component
import { useNumberFormat } from '@docyrus/ui/hooks/use-number-format';
function Total({ amount, currency }: { amount: number; currency: string }) {
const { formatNumber } = useNumberFormat();
return <span>{formatNumber(amount, { variant: 'currency', currency })}</span>;
}Standard setup — let <DocyrusTenantProvider> do it
If your app already wraps its root in <DocyrusTenantProvider>, you don't have to do anything. Tenant-aware formatNumber is already wired.
Custom provider (Intl, dinero.js, …)
import { NumberFormatProvider } from '@docyrus/ui/hooks/use-number-format';
function App({ children }) {
return (
<NumberFormatProvider
formatNumber={(value, opts) => {
const variant = opts?.variant ?? 'number';
const num = Number(value);
if (Number.isNaN(num)) return String(value ?? '');
return new Intl.NumberFormat('en-US', {
style: variant === 'currency' ? 'currency' : variant === 'percent' ? 'percent' : 'decimal',
currency: opts?.currency
}).format(variant === 'percent' ? num : num);
}}>
{children}
</NumberFormatProvider>
);
}API Reference
useNumberFormat()
Returns NumberFormatContextValue.
| Field | Type | Description |
|---|---|---|
formatNumber | (value: unknown, options?: NumberFormatOptions) => string | Formats a number using the active provider's strategy. |
NumberFormatOptions
| Field | Type | Description |
|---|---|---|
variant | 'number' | 'currency' | 'percent' | Output style. Default 'number'. 'percent' multiplies the input by 100 and appends %. |
currency | string | ISO 4217 currency code, used when variant === 'currency'. |
decimalPrecision | number | Override the locale's default fraction digits. Pass 0 for identifier-like numerics. |
thousandSeparator | string | Override the locale's default thousands grouping. Empty string disables grouping. |
<NumberFormatProvider>
| Prop | Type | Description |
|---|---|---|
formatNumber | NumberFormatFn | Required. The implementation that backs useNumberFormat() inside the tree. |
children | ReactNode | Tree to wrap. |
isDefaultNumberFormatContext(ctx)
Returns true when the value returned by useNumberFormat() is the built-in no-provider sentinel (raw String(value) renderer) rather than a real provider. Internal hooks use this to avoid shadowing a cell's locale-aware fallback when no provider is mounted. Most apps don't need to call it directly.
Type Exports
| Type | Description |
|---|---|
NumberFormatFn | Signature of the formatter function. |
NumberFormatOptions | Options accepted by formatNumber. |
NumberFormatContextValue | Shape returned by useNumberFormat(). |