npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

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.

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-lite
yarn add react-native-format-utils-lite

No 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-DE genuinely places the symbol after the number (1.234,56 €) — that is the correct German convention, not a bug. Pass locale: '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. Intl inserts 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. formatCurrency normalises these to a plain space so output is stable across platforms and safe to compare as a string.
  • Intl fallback. If Intl.NumberFormat is missing or throws, formatCurrency falls back to manual grouping — Indian grouping for INR and *-IN locales, Western grouping otherwise.
  • Grapheme segmentation. truncateText uses Intl.Segmenter where 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