@elastic/numeral
Elastic's Kibana-maintained fork of numeral.js for formatting and manipulating numbers, currency, percentages, times, and byte sizes.
Repository Health
Technical Analysis
@elastic/numeral is Elastic’s published fork of the classic numeral.js formatting library, maintained for use inside Kibana and other Elastic Stack front-end code. It wraps a raw JavaScript number in a small Numeral object and lets you render it through pattern strings like 0,0.00, $0,0.00, 0%, 00:00:00, or 0b to get thousands separators, currency symbols, percentages, clock time, and byte-unit suffixes (KB/MB/GB) respectively — then parse the same strings back into numbers with unformat.
Beyond formatting, it exposes simple arithmetic helpers (add, subtract, multiply, divide, difference) built on a correction-factor technique that avoids common floating-point rounding errors, plus a pluggable locale system (numeral.language()) backed by more than two dozen bundled locale packs under languages/ covering different thousands/decimal delimiters, currency symbols, and ordinal-suffix rules.
What You Get
- A single
numeral(value)factory that wraps any number and exposes chainable.format()/.unformat()methods - Pattern-string formatting for currency (
$0,0.00), percentages (0%), clock time (00:00:00), and byte sizes (0b) without extra plugins - Floating-point-safe arithmetic helpers —
add,subtract,multiply,divide,difference— using a correction-factor technique to avoid rounding drift - Over two dozen bundled locale packs (
languages/*.js) covering distinct thousands/decimal delimiters, currency symbols, and ordinal rules - A bundled TypeScript ambient declaration (
index.d.ts) for typed consumption in TS projects
Common Use Cases
- Formatting currency and large counts in Kibana dashboards and other Elastic Stack UI code
- Rendering byte-size fields (log/index sizes, transfer volumes) as human-readable KB/MB/GB strings
- Displaying percentages and time durations in reporting or monitoring widgets
- Round-tripping user-typed formatted strings (e.g. “$1,234.50”) back into raw numbers for calculations
Under The Hood
Architecture
numeral.js is a single-file monolith wrapped in an IIFE factory (numeralFactory) that closes over module-level state — a languages registry, currentLanguage, zeroFormat, and defaultFormat — and exposes one global numeral function/constructor. The Numeral constructor wraps a raw JS number in this._value, and all formatting logic branches on pattern-string content ($, %, :, b) inside formatNumeral/unformatNumeral, delegating to private helper functions (formatCurrency, formatPercentage, formatTime, formatBytes, formatNumber). Locale packs live in languages.js and languages/*.js as flat data objects (delimiters, abbreviations, an ordinal function, currency symbol) loaded into the languages{} map via loadLanguage(), with currentLanguage as a single mutable string swapped by numeral.language(). There is no dependency injection or plugin architecture beyond registering a language object — the whole design is procedural string-pattern dispatch over one shared prototype (numeral.fn = Numeral.prototype), so a change to the core format dispatch or the language-loading contract affects every consumer at once.
Tech Stack
The package is plain, dependency-free ES5 JavaScript — the entire runtime is numeral.js plus the locale data in languages.js/languages/*.js and a hand-written TypeScript declaration (index.d.ts) for typed consumers. Build and dev tooling run through Grunt (Gruntfile.js), using grunt-contrib-jshint for linting and grunt-contrib-nodeunit as the test runner; CI is Travis (.travis.yml, grunt travis --verbose) against Node “stable” and Node 10. There is no bundler or transpiler — the package is consumed directly as CommonJS (main: ./numeral.js) in Node or as a browser global, and is published as Elastic’s Kibana-vendored fork of the original numeral.js project.
Code Quality
Tests exist under tests/numeral/ (byteunits.js, format.js, manipulate.js, misc.js, unformat.js), run through grunt-contrib-nodeunit, and cover formatting, unformatting, byte-unit suffixes, and arithmetic manipulation with a reasonably thorough assertion set for a library this size. There is no TypeScript source — only the hand-authored ambient index.d.ts — and the codebase predates ES6 conventions (var-based, a manual Array.prototype.reduce polyfill for older browsers). Error handling is minimal: numeral.language() throws a plain Error for an unrecognized language key, and there’s little other explicit handling elsewhere; floating-point correctness relies on hand-rolled toFixed/correctionFactor helpers adapted from an external gist-style technique. jshint, run through Grunt, is the only configured linter.
What Makes It Unique
This fork isn’t architecturally novel versus the many other JavaScript number-formatting libraries, and native Intl.NumberFormat now covers much of the same ground. Its value is narrower and organizational: Elastic maintains its own patched, independently versioned build of the small, dependency-free numeral.js API — bundling currency/percentage/time/byte pattern-string formatting, floating-point-safe arithmetic, and swappable locale packs in one package — specifically so Kibana and related Elastic Stack front-end code have a stable, self-controlled dependency rather than relying on the (now less actively maintained) upstream project.