react-native-format-utils-lite
v1.0.0
Published
Lightweight, zero-dependency formatting helpers for React Native — currency (including Indian lakh/crore grouping), compact numbers, phone numbers, byte sizes and text truncation.
Maintainers
Readme
react-native-format-utils-lite
Lightweight, zero-dependency formatting helpers for React Native — and for plain JS/TS too.
- 🪶 Tiny — zero runtime dependencies
- 📱 No native code — pure TypeScript, no linking, works with Expo
- 🌳 Tree-shakeable — one function per module,
sideEffects: false - 🇮🇳 Indian formats first-class — lakh/crore grouping,
1.2L/3.4Cr,+91 98765 43210 - 🛡️ Never throws — every function is pure and returns a sensible fallback for bad input
- 📦 CommonJS + ESM +
.d.ts— built with react-native-builder-bob
Installation
npm install react-native-format-utils-liteyarn add react-native-format-utils-liteNo native module to link, no pod install. react-native is an optional peer dependency, so this works just as well in a Node or web project.
Quick start
import {
formatCurrency,
formatCompactNumber,
formatPhoneNumber,
truncateText,
formatBytes,
} from 'react-native-format-utils-lite';
formatCurrency(123456.78); // '₹1,23,456.78'
formatCompactNumber(120000, { style: 'indian' }); // '1.2L'
formatPhoneNumber('9876543210'); // '+91 98765 43210'
truncateText('React Native is great', 10); // 'React Nat…'
formatBytes(1536); // '1.5 KB'Functions
formatCurrency(amount, options?)
Formats a number as currency, with correct digit grouping for the locale — including Indian lakh/crore grouping. Uses Intl.NumberFormat under the hood, with a manual fallback for engines shipped without full ICU data (some older React Native Android builds).
TypeScript
import { formatCurrency } from 'react-native-format-utils-lite';
formatCurrency(123456.78); // '₹1,23,456.78' (INR is the default)
formatCurrency(1234.56, { currency: 'USD' }); // '$1,234.56'
formatCurrency(1234.56, { currency: 'EUR' }); // '1.234,56 €'
formatCurrency(1234, { currency: 'JPY' }); // '¥1,234'
// Override the locale independently of the currency
formatCurrency(1234.56, { currency: 'USD', locale: 'de-DE' }); // '1.234,56 $'
// Fixed precision
formatCurrency(1234.5678, { currency: 'USD', decimals: 3 }); // '$1,234.568'
// Graceful on bad input
formatCurrency(null); // ''
formatCurrency(undefined, { fallback: 'N/A' }); // 'N/A'JavaScript
import { formatCurrency } from 'react-native-format-utils-lite';
function PriceTag({ amount }) {
return <Text>{formatCurrency(amount, { currency: 'INR' })}</Text>;
}Note on EUR.
de-DEgenuinely places the symbol after the number (1.234,56 €) — that is the correct German convention, not a bug. Passlocale: 'en-IE'for€1,234.56.
formatCompactNumber(value, options?)
Shortens large numbers for compact UI — follower counts, view counts, dashboard tiles.
TypeScript
import { formatCompactNumber } from 'react-native-format-utils-lite';
// Western (default)
formatCompactNumber(1200); // '1.2K'
formatCompactNumber(3_400_000); // '3.4M'
formatCompactNumber(1_100_000_000); // '1.1B'
// Indian
formatCompactNumber(120_000, { style: 'indian' }); // '1.2L'
formatCompactNumber(34_000_000, { style: 'indian' }); // '3.4Cr'
// Precision
formatCompactNumber(1234, { decimals: 2 }); // '1.23K'
formatCompactNumber(2_000_000, { keepTrailingZeros: true }); // '2.0M'
// Negatives and edges
formatCompactNumber(-1200); // '-1.2K'
formatCompactNumber(999_999); // '1M' (promoted, never '1000K')JavaScript
import { formatCompactNumber } from 'react-native-format-utils-lite';
function FollowerCount({ count }) {
return (
<Text>{formatCompactNumber(count, { style: 'indian' })} followers</Text>
);
}formatPhoneNumber(value, options?)
Formats a phone number into its national convention. Input can be messy — spaces, dashes, brackets, a leading +, a dialling code, or a domestic trunk 0 are all tolerated.
If the digits do not match the expected length, the original input is returned unchanged rather than being mangled into a wrong-looking number.
TypeScript
import { formatPhoneNumber } from 'react-native-format-utils-lite';
formatPhoneNumber('9876543210'); // '+91 98765 43210'
formatPhoneNumber('+91-98765-43210'); // '+91 98765 43210'
formatPhoneNumber('09876543210'); // '+91 98765 43210' (trunk 0 stripped)
formatPhoneNumber('5551234567', { country: 'US' }); // '+1 (555) 123-4567'
formatPhoneNumber('5551234567', { country: 'US', includeCountryCode: false });
// '(555) 123-4567'
formatPhoneNumber('12345'); // '12345' (unchanged — not formattable)JavaScript
import { formatPhoneNumber } from 'react-native-format-utils-lite';
function ContactRow({ phone }) {
return <Text>{formatPhoneNumber(phone, { country: 'IN' })}</Text>;
}truncateText(text, maxLength, ellipsis?)
Safe truncation that counts user-perceived characters, not UTF-16 units. Emoji — including multi-codepoint ZWJ sequences like 👨👩👧👦 — are never split into broken halves. The result, ellipsis included, never exceeds maxLength.
TypeScript
import { truncateText } from 'react-native-format-utils-lite';
truncateText('React Native is great', 10); // 'React Nat…'
truncateText('Short', 10); // 'Short' (unchanged)
truncateText('React Native', 8, '...'); // 'React...'
truncateText('React Native', 5, ''); // 'React' (hard cut)
// Emoji-safe
truncateText('👨👩👧👦 family time', 5); // '👨👩👧👦 fa…'JavaScript
import { truncateText } from 'react-native-format-utils-lite';
function PostPreview({ body }) {
return <Text numberOfLines={1}>{truncateText(body, 80)}</Text>;
}formatBytes(bytes, options?)
Formats a byte count as a human-readable size — upload progress, cache sizes, attachment labels.
TypeScript
import { formatBytes } from 'react-native-format-utils-lite';
formatBytes(0); // '0 B'
formatBytes(1536); // '1.5 KB'
formatBytes(2_411_724); // '2.3 MB'
formatBytes(1_073_741_824); // '1 GB'
formatBytes(1536, { decimals: 0 }); // '2 KB'
formatBytes(1024, { keepTrailingZeros: true }); // '1.0 KB'
formatBytes(1_500_000, { binary: false }); // '1.5 MB' (base 1000)JavaScript
import { formatBytes } from 'react-native-format-utils-lite';
function Attachment({ file }) {
return (
<Text>
{file.name} · {formatBytes(file.size)}
</Text>
);
}API reference
formatCurrency(amount, options?)
| Parameter | Type | Default | Description |
| --------- | --------- | ------- | -------------------------------------------------- |
| amount | unknown | — | Value to format. Numbers and numeric strings work. |
| options | object | {} | See below. |
| Option | Type | Default | Description |
| ---------- | -------- | --------------------- | -------------------------------------------------------------------------------------- |
| currency | string | 'INR' | ISO 4217 code, e.g. 'USD', 'EUR', 'JPY'. |
| locale | string | derived from currency | BCP 47 tag. Defaults: INR→en-IN, USD→en-US, EUR→de-DE, GBP→en-GB, JPY→ja-JP. |
| decimals | number | currency default | Fixed fraction digits. Omit for the currency's own convention (2 for USD, 0 for JPY). |
| fallback | string | '' | Returned when the input is not a usable number. |
Returns string — the formatted amount, or fallback for invalid input.
formatCompactNumber(value, options?)
| Parameter | Type | Default | Description |
| --------- | --------- | ------- | ---------------------------------------- |
| value | unknown | — | Number to shorten. Numeric strings work. |
| options | object | {} | See below. |
| Option | Type | Default | Description |
| ------------------- | ----------------------- | ----------- | ----------------------------------------------- |
| style | 'western' \| 'indian' | 'western' | 'western' → K/M/B/T. 'indian' → K/L/Cr. |
| decimals | number | 1 | Fraction digits on the shortened value. |
| keepTrailingZeros | boolean | false | Keep 1.0K instead of trimming to 1K. |
| fallback | string | '' | Returned when the input is not a usable number. |
Returns string — the compact number, or fallback for invalid input.
Thresholds — western: 1e3 K, 1e6 M, 1e9 B, 1e12 T. Indian: 1e3 K, 1e5 L, 1e7 Cr. Values that round up to the next unit are promoted (999999 → '1M', never '1000K').
formatPhoneNumber(value, options?)
| Parameter | Type | Default | Description |
| --------- | --------- | ------- | ------------------------------------------- |
| value | unknown | — | Number to format. Strings and numbers work. |
| options | object | {} | See below. |
| Option | Type | Default | Description |
| -------------------- | -------------- | ------- | --------------------------------------- |
| country | 'IN' \| 'US' | 'IN' | National format to apply. |
| includeCountryCode | boolean | true | Prefix the dialling code (+91, +1). |
Returns string — the formatted number; the original input when the digits do not match the country's expected length; '' for non-string/non-number input.
| Country | National length | Output shape |
| ------- | --------------- | ------------------- |
| IN | 10 | +91 98765 43210 |
| US | 10 | +1 (555) 123-4567 |
truncateText(text, maxLength, ellipsis?)
| Parameter | Type | Default | Description |
| ----------- | --------- | ------- | ------------------------------------------------------------------------------------------- |
| text | unknown | — | Text to truncate. Non-strings yield ''. |
| maxLength | number | — | Maximum result length, including the ellipsis. <= 0, NaN and Infinity yield ''. |
| ellipsis | string | '…' | Appended when truncation occurs. Pass '' for a hard cut. |
Returns string — the truncated text, or the original when it already fits.
formatBytes(bytes, options?)
| Parameter | Type | Default | Description |
| --------- | --------- | ------- | --------------------------------- |
| bytes | unknown | — | Byte count. Numeric strings work. |
| options | object | {} | See below. |
| Option | Type | Default | Description |
| ------------------- | --------- | ------- | --------------------------------------------------------------------- |
| decimals | number | 1 | Fraction digits on the scaled value. Raw bytes never show a fraction. |
| binary | boolean | true | true scales by 1024; false by 1000. |
| keepTrailingZeros | boolean | false | Keep 1.0 KB instead of trimming to 1 KB. |
| fallback | string | '' | Returned when the input is not a usable number. |
Returns string — the formatted size, or fallback for invalid input. Units: B, KB, MB, GB, TB, PB, EB, ZB, YB.
Invalid input behaviour
Every function is pure and never throws. The table below is what you get for bad input:
| Function | null / undefined / NaN / Infinity | Wrong-shaped but valid input |
| --------------------- | ----------------------------------------- | -------------------------------------------------- |
| formatCurrency | fallback (default '') | Unknown currency code → manual fallback formatting |
| formatCompactNumber | fallback (default '') | — |
| formatPhoneNumber | '' | Original input returned unchanged |
| truncateText | '' | maxLength <= 0 → '' |
| formatBytes | fallback (default '') | Negative → signed result (-1.5 KB) |
Tree-shaking
Each function lives in its own module and the package declares sideEffects: false, so a bundler that supports tree-shaking will include only what you import:
import { formatBytes } from 'react-native-format-utils-lite';
// Only formatBytes and its tiny shared helpers land in your bundle.Notes
- Whitespace normalisation.
Intlinserts a non-breaking (U+00A0) or narrow-no-break (U+202F) space around currency symbols, and the exact codepoint differs between Hermes, JSC and V8.formatCurrencynormalises these to a plain space so output is stable across platforms and safe to compare as a string. Intlfallback. IfIntl.NumberFormatis missing or throws,formatCurrencyfalls back to manual grouping — Indian grouping for INR and*-INlocales, Western grouping otherwise.- Grapheme segmentation.
truncateTextusesIntl.Segmenterwhere available so ZWJ emoji sequences stay intact, and degrades to code-point counting where it is not.
Compatibility
| | Supported |
| ------------------- | ---------------------------------------------- |
| React Native | >=0.60.0 (optional peer) |
| Expo | ✅ — no native code |
| Plain JS / TS, Node | ✅ |
| Engines without ICU | ✅ — formatCurrency falls back automatically |
Contributing
npm install # install dependencies
npm test # run the Jest suite
npm run lint # ESLint + Prettier
npm run build # build CJS, ESM and .d.ts into lib/License
MIT © Melby Thomas
