JavaScript Number Format Library


hcg-number-formatter is a lightweight, zero-dependency JavaScript library for formatting numbers. It turns raw numbers into clean, human-readable strings - thousands separators, currency, compact abbreviations (K/M/B/T), ordinals (1st, 2nd, 3rd), file sizes, zero-padding, fixed decimals, and it can parse formatted strings back into numbers. It works in the browser with a single <script> tag and in Node.js via npm, with no dependencies and full TypeScript definitions included.

What is hcg-number-formatter?

hcg-number-formatter is a small JavaScript utility that handles all the common ways you need to display numbers in a user interface. Instead of writing repetitive helper code every time you need to show a price, a follower count, a file size, or a ranking, you call one short function and get a correctly formatted string back.

It bundles eight focused functions - format, currency, compact, ordinal, fileSize, pad, fixed, and parse - each covering a real-world formatting task. The whole library is around 3 KB, has no dependencies, and runs the same way in the browser and in Node.js. It also fixes well-known JavaScript number pitfalls, such as (1.005).toFixed(2) returning "1.00" and large numbers like 1e21 printing in scientific notation.

Features

  • Thousands separators with custom separator and decimal characters
  • Currency formatting with 26 built-in currency codes
  • Compact abbreviations: 1,500,000 to "1.5M"
  • Ordinals: 1 to "1st", 22 to "22nd"
  • Human-readable file sizes (IEC and SI)
  • Zero-padding and fixed decimal places
  • Parse formatted strings back into numbers (US and European)
  • Zero dependencies, ~3 KB, works everywhere

Demo

Number formats demo

Options
Presets
Options
Presets
Options
Presets
Options
Presets
Options
Presets
Options
Presets
Options
Presets
Options
Presets
Options
Presets
Options
Presets
Options
Presets
Options
Presets

Normal function vs hcg-number-formatter

Plain JavaScript can format numbers, but it is verbose, easy to get wrong, and inconsistent across tasks. Here is the same work done with hand-written code versus hcg-number-formatter.

Thousands separators and decimals

JavaScript
// Plain JavaScript
(1234567.89).toLocaleString('en-US', {
    minimumFractionDigits: 2,
    maximumFractionDigits: 2
}); // "1,234,567.89"

// hcg-number-formatter
format(1234567.89, { decimals: 2 }); // "1,234,567.89"

Compact abbreviations (1.5M)

JavaScript
// Plain JavaScript - manual thresholds and rounding
function compact(n) {
    if (n >= 1e9) return (n / 1e9).toFixed(1) + 'B';
    if (n >= 1e6) return (n / 1e6).toFixed(1) + 'M';
    if (n >= 1e3) return (n / 1e3).toFixed(1) + 'K';
    return String(n);
}
compact(999999); // "1000.0K"  (wrong - should roll over to 1M)

// hcg-number-formatter - boundary-safe
compact(999999); // "1M"

Currency with a negative accounting style

JavaScript
// Plain JavaScript - no built-in accounting/parentheses style
const value = -500;
const text = '$' + Math.abs(value).toFixed(2);
const result = value < 0 ? '(' + text + ')' : text; // "($500.00)"

// hcg-number-formatter
currency(-500, { negativeStyle: 'parens' }); // "($500.00)"

Rounding correctness

JavaScript
// Plain JavaScript - binary float rounding bug
(1.005).toFixed(2); // "1.00"  (incorrect)

// hcg-number-formatter - decimal-safe rounding
fixed(1.005, { decimals: 2 }); // "1.01"

Why use hcg-number-formatter?

  • Less code, fewer bugs. One readable function call replaces blocks of manual math, threshold checks, and string building.
  • Consistent everywhere. The same API and output run in the browser and Node.js, so server-rendered and client-rendered numbers match.
  • Correct by default. It handles the cases plain JavaScript gets wrong: half-up decimal rounding, compact boundary rollover, very large and very small numbers, and accounting-style negatives.
  • No dependencies, tiny footprint. About 3 KB with zero third-party packages, so it will not bloat your bundle or pull in a supply chain.
  • Covers many tasks in one place. Currency, compact, ordinals, file sizes, padding, fixed decimals, and parsing - without reaching for several different libraries.
  • Two-way. parse() turns formatted strings back into numbers, including US and European styles, so user input round-trips cleanly.

hcg-number-formatter advantages

  • Zero dependencies - nothing else to install or audit.
  • Lightweight - roughly 3 KB, loads instantly.
  • Universal - works via a single <script> tag, CommonJS require, or ES module import.
  • TypeScript ready - full type definitions included.
  • 26 built-in currencies - USD, EUR, GBP, JPY, INR, and more, with correct symbols and decimal defaults.
  • Locale aware - custom thousands separator and decimal character; auto-detects European input in parse().
  • Accurate rounding - decimal-safe, so financial values are not silently rounded down.
  • Handles extremes - no scientific notation leaking into output for huge or tiny numbers.
  • Tested - backed by an automated test suite covering edge cases.
  • MIT licensed - free for personal and commercial use.

Comparison with other options

How hcg-number-formatter compares to the common ways people format numbers in JavaScript - the built-in Intl.NumberFormat and popular libraries such as numeral.js, numbro, and accounting.js.

Capability hcg-number-formatter Intl.NumberFormat numeral.js / numbro
Bundle size~3 KB, zero dependenciesBuilt in (0 KB)~9-12 KB, may add locales
Thousands separatorsYes, custom separator/decimalYes (locale based)Yes
Currency with accounting negativesYes, parens stylePartialYes
Compact K/M/B/TYes, boundary-safeYes (notation: 'compact')Yes
Ordinals (1st, 2nd)YesNoPartial / plugin
File sizes (KiB/MiB)Yes (IEC and SI)NoPartial
Percent, roundTo, clamp, durationYesPercent onlyPartial
Parse formatted string to numberYes (US and European)NoYes (numeral)
Decimal-safe roundingYes (1.005 to 1.01)No (1.005 to 1.00)Varies
TypeScript definitionsIncludedBuilt inVaries
LicenseMITNative APIMIT

Intl.NumberFormat is great for locale-aware number and currency output and adds nothing to your bundle, but it does not handle ordinals, file sizes, durations, or parsing, and it inherits the binary rounding quirk. Libraries like numeral.js and numbro cover more, but are larger and less actively maintained. hcg-number-formatter aims for the middle: many real-world formatters in one tiny, dependency-free package with correct rounding.

Installation

Node.js Usage

Command line
npm install hcg-number-formatter
JavaScript
// CommonJS
const { format, currency, compact, ordinal, fileSize, pad, fixed, parse } = require('hcg-number-formatter');

// ES Modules
import { format, currency, compact, ordinal, fileSize, pad, fixed, parse } from 'hcg-number-formatter';

format(1234567.89); // "1,234,567.89"

Vanilla JavaScript (browser)

Load the script from a CDN, then use the global NumberFormatter object.

HTML
<script src="https://cdn.jsdelivr.net/npm/hcg-number-formatter/index.js"></script>
JavaScript
const { format, currency, compact, ordinal, fileSize, pad, fixed, percent, roundTo, clamp, duration, parse } = NumberFormatter;

console.log(format(1234567.89));  // "1,234,567.89"

currency(1234.5);                  // "$1,234.50"
compact(1500000);                  // "1.5M"
ordinal(3);                        // "3rd"
fileSize(1024);                    // "1 KiB"
pad(5, { length: 3 });             // "005"
fixed(3.14159, { decimals: 2 });   // "3.14"
percent(0.1234);                   // "12.34%"
roundTo(1234, { nearest: 50 });    // 1250
clamp(15, 0, 10);                  // 10
duration(3661);                    // "1h 1m 1s"
parse('$1,234.56');                // 1234.56

// or usage like this
// NumberFormatter.format(1234567); // "1,234,567"

API and Usage

format(number, options)

Adds thousands separators and optional decimal places.

JavaScript
format(1234567.89)                              // "1,234,567.89"
format(1234567, { decimals: 0 })                // "1,234,567"
format(1234.5, { decimals: 2 })                 // "1,234.50"
format(1234.5, { separator: '.', decimal: ',' })// "1.234,5"  (European)
format(-9876543.21)                             // "-9,876,543.21"
format(1e21)                                    // "1,000,000,000,000,000,000,000"
Option Type Default Description
decimals number auto Number of decimal places
separator string ',' Thousands separator
decimal string '.' Decimal point character

currency(number, options)

Formats a number as currency.

JavaScript
currency(1234.5)                                       // "$1,234.50"
currency(1234.5, { symbol: '€', position: 'after' })   // "1,234.50€"
currency(1234.5, { code: 'JPY' })                      // "¥1,235"
currency(1234.5, { code: 'EUR' })                      // "€1,234.50"
currency(1234.5, { code: 'EUR', separator: '.', decimal: ',' }) // "€1.234,50"
currency(-500, { negativeStyle: 'parens' })            // "($500.00)"
Option Type Default Description
symbol string '$' Currency symbol
position 'before' | 'after' 'before' Symbol placement
decimals number 2 Decimal places
code string - ISO 4217 code — auto-sets symbol and decimals
negativeStyle 'minus' | 'parens' 'minus' How to show negative values
separator string ',' Thousands separator

compact(number, options)

Abbreviates large numbers with K/M/B/T units.

JavaScript
compact(1200)                       // "1.2K"
compact(1500000)                    // "1.5M"
compact(2000000000)                 // "2B"
compact(999)                        // "999"
compact(1200, { precision: 2 })     // "1.20K"
compact(999999)                     // "1M"
Option Type Default Description
precision number 1 Decimal places in output
units string[] ['','K','M','B','T'] Custom unit labels
threshold number 1000 Minimum value to abbreviate

ordinal(number)

Converts a number to its ordinal string.

JavaScript
ordinal(1)    // "1st"
ordinal(2)    // "2nd"
ordinal(3)    // "3rd"
ordinal(11)   // "11th"
ordinal(21)   // "21st"
ordinal(112)  // "112th"

fileSize(bytes, options)

Formats a byte count as a human-readable file size.

JavaScript
fileSize(0)                             // "0 Bytes"
fileSize(1024)                          // "1 KiB"
fileSize(1500000)                       // "1.43 MiB"
fileSize(1500000, { standard: 'si' })   // "1.5 MB"
fileSize(1073741824)                    // "1 GiB"
Option Type Default Description
standard 'iec' | 'si' 'iec' iec=KiB/MiB (base-1024), si=KB/MB (base-1000)
decimals number 2 Decimal places

pad(number, options)

Pads a number with leading characters to a fixed length.

JavaScript
pad(5, { length: 3 })                 // "005"
pad(42, { length: 5 })                // "00042"
pad(7, { length: 4, char: '*' })      // "***7"
pad(12345, { length: 3 })             // "12345"
Option Type Default Description
length number 2 Total output length
char string '0' Pad character

fixed(number, options)

Formats a number to a fixed number of decimal places (with decimal-safe rounding).

JavaScript
fixed(3.14159, { decimals: 2 })   // "3.14"
fixed(3.1, { decimals: 4 })       // "3.1000"
fixed(1.005, { decimals: 2 })     // "1.01"
Option Type Default Description
decimals number 2 Number of decimal places

percent(number, options)

Formats a 0-1 ratio as a percentage. By default it multiplies by 100 and trims trailing zeros; pass scale: false when the value is already a percentage.

JavaScript
percent(0.1234)                    // "12.34%"
percent(0.1234, { decimals: 1 })   // "12.3%"
percent(1)                         // "100%"
percent(0.05, { decimals: 2 })     // "5.00%"
percent(25, { scale: false })      // "25%"
percent(-0.075)                    // "-7.5%"
Option Type Default Description
decimals number trim Decimal places (default trims trailing zeros)
scale boolean true Multiply by 100 first; set false if the value is already a percentage
space boolean false Insert a space before the %
separator string ',' Thousands separator
decimal string '.' Decimal point character

roundTo(number, options)

Rounds a number to the nearest step or to a number of decimal places. Returns a number, not a string.

JavaScript
roundTo(1234, { nearest: 50 })              // 1250
roundTo(1234, { nearest: 100 })             // 1200
roundTo(2.345, { decimals: 1 })             // 2.3
roundTo(1234, { nearest: 50, mode: 'floor' }) // 1200
roundTo(1201, { nearest: 50, mode: 'ceil' })  // 1250
roundTo(0.07, { nearest: 0.05 })            // 0.05
Option Type Default Description
nearest number Round to the nearest multiple of this step
decimals number 0 Round to this many decimals (ignored when nearest is set)
mode 'round' | 'floor' | 'ceil' 'round' Rounding direction

clamp(number, min, max)

Constrains a number to the inclusive range between min and max. Either bound may be omitted. Returns a number.

JavaScript
clamp(15, 0, 10)            // 10
clamp(-5, 0, 10)            // 0
clamp(7, 0, 10)             // 7
clamp(3, 5)                 // 5   (min only)
clamp(100, undefined, 50)   // 50  (max only)

duration(seconds, options)

Formats a count of seconds as a human-readable duration in short, clock, or long style.

JavaScript
duration(3661)                       // "1h 1m 1s"
duration(90)                         // "1m 30s"
duration(3661, { style: 'clock' })   // "1:01:01"
duration(90, { style: 'clock' })     // "1:30"
duration(7200, { style: 'long' })    // "2 hours"
duration(93784)                      // "1d 2h 3m 4s"
Option Type Default Description
style 'short' | 'clock' | 'long' 'short' Output style
units string[] ['d','h','m','s'] Which units to use

parse(string, options)

Parses a formatted number string back into a number. Strips currency symbols, separators, and whitespace. Parentheses are treated as negative (accounting style).

JavaScript
parse('$1,234.56')                    // 1234.56
parse('1,000,000')                    // 1000000
parse('($500.00)')                    // -500
parse('1.234,56', { decimal: ',' })   // 1234.56  (European)
parse('abc')                          // NaN

Options: separator, decimal (default "."; use "," for European format).


Frequently Asked Questions (FAQ)

What is hcg-number-formatter?

hcg-number-formatter is a small, zero-dependency JavaScript library for formatting numbers. It bundles focused functions - format, currency, compact, ordinal, fileSize, pad, fixed, percent, roundTo, clamp, duration, and parse - that turn raw numbers into clean, human-readable strings. It is about 3 KB and runs the same way in the browser and in Node.js.

Why use hcg-number-formatter instead of plain JavaScript?

Plain JavaScript number formatting is verbose and easy to get wrong. hcg-number-formatter replaces blocks of manual math with one readable function call, behaves consistently in the browser and Node.js, and fixes common pitfalls such as (1.005).toFixed(2) returning '1.00', compact boundary rollover, and scientific notation on very large or small numbers.

Is hcg-number-formatter free?

Yes. hcg-number-formatter is released under the MIT license and is free for both personal and commercial use.

Does hcg-number-formatter have any dependencies?

No. The library has zero third-party dependencies and is roughly 3 KB, so it does not bloat your bundle or add supply-chain risk.

How do I install hcg-number-formatter?

Install it from npm with 'npm install hcg-number-formatter', or load it in the browser with a single script tag from a CDN and use the global NumberFormatter object.

Does hcg-number-formatter support currencies and locales?

Yes. It includes 26 built-in currency codes such as USD, EUR, GBP, JPY, and INR with correct symbols and decimal defaults, supports custom thousands separators and decimal characters, and auto-detects European number input when parsing.