table

Renders arrays of data as clean, precisely aligned ASCII/Unicode tables for terminal output, with full ANSI-color and fullwidth-character awareness.

Library
npm
v6.9.0
973stars
BSD 3-Clause License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
45/100Fair
Development Activity0
Maintenance32
Community60
Maturity60
Momentum28

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
71/100Good
Architecture84
Code Quality90
Innovation65
Learning Curve45

table is a TypeScript library that turns two-dimensional arrays of arbitrary data into readable, borderable text tables for terminal or log output. It handles the parts that are easy to get wrong when hand-rolling this yourself: measuring true display width for fullwidth (CJK) characters and ANSI-colored strings (so a chalk-colored cell doesn’t blow out the column width), wrapping long content at word boundaries or a fixed character count, aligning and vertically centering cell contents, and drawing configurable borders including merged spanning cells across rows and columns.

Beyond the one-shot table() function, it exposes a createStream() API for incrementally appending rows to a live-updating table in place — useful for progress displays or tailing output — and a getBorderCharacters() helper for picking from built-in border styles (honeywell, norc, ramac, void) or supplying your own. Configuration is validated against a JSON Schema compiled ahead-of-time with ajv, so malformed config throws a clear, specific error rather than failing silently deep in the rendering pipeline.

What You Get

  • A table(data, config) function that renders any unknown[][] as an aligned, bordered text table in one call
  • A createStream(config) API for writing rows incrementally to a live, in-place-updating terminal table
  • getBorderCharacters(name) presets (honeywell, norc, ramac, void) plus fully custom border character sets
  • Column-level configuration: width, alignment, vertical alignment, padding, truncation, and word-wrapping
  • Spanning-cell support to merge content across multiple rows and/or columns in a single table
  • ANSI-escape-aware and fullwidth-character-aware width calculation so colored or CJK content still aligns correctly
  • Ahead-of-time JSON-Schema config validation (via ajv) that throws descriptive errors for invalid configuration

Common Use Cases

  • CLI output formatting - printing structured results (lists of records, diffs, comparisons) as readable tables in command-line tools
  • Test and build reporters - rendering pass/fail summaries, coverage tables, or benchmark results in terminal test runners
  • Log and debug output - dumping arrays of objects as scannable tables during local development or CI logs
  • Live progress displays - using createStream() to show rows appended in real time (e.g. per-file processing status) without re-rendering the whole table
  • Data comparison tables - laying out before/after or multi-column comparisons with merged header cells via spanning-cell config

Under The Hood

Architecture table.ts orchestrates a linear, purely-functional pipeline: validateTableData -> stringifyTableData -> injectHeaderConfig -> makeTableConfig -> truncateTableData -> calculateRowHeights -> spanningCellManager row-height/index mapping -> mapDataUsingRowHeights -> alignTableData -> padTableData -> calculateOutputColumnWidths -> drawTable, with each stage a small, single-purpose module that transforms the same immutable rows array and a shared config object built by makeTableConfig from an ajv-validated JSON Schema. createStream.ts reuses the same compute-layer functions (stringifyTableData, alignTableData, padTableData, drawRow/drawBorder) for a stateful incremental writer, keeping process.stdout.write side effects confined to a thin imperative shell around the pure core. The one genuinely stateful abstraction is spanningCellManager, which calculateRowHeights, mapDataUsingRowHeights, alignSpanningCell, and drawTable all consult for merged-cell queries — it’s the piece that would ripple outward if the spanning-cell model changed.

Tech Stack Written in strict-mode TypeScript (ES2018 target, CommonJS output, noUnusedLocals/noImplicitReturns enabled) with no runtime framework dependency. Configuration correctness is delegated to ajv: JSON Schemas under src/schemas/ (config.json, streamConfig.json, shared.json) are compiled ahead-of-time via ajv compile into a standalone src/generated/validators.js, avoiding runtime schema-compile cost in consumers. Display-width correctness comes from string-width (fullwidth/CJK-aware) and slice-ansi/strip-ansi (ANSI-safe truncation and measurement), with lodash.truncate for plain text truncation. The package ships plain tsc output (dist/src) referenced by both main and module in package.json rather than a bundled build.

Code Quality The test/ directory mirrors src/ nearly 1:1 (48 test files for ~35 src modules), using mocha, chai, and sinon, with nyc (Istanbul) enforcing a 95%-line-coverage gate as part of npm test. Error handling is explicit rather than swallowed: validateTableData throws typed errors with specific messages for non-array input, inconsistent column counts, and embedded control characters, and malformed table config is rejected by the ajv-generated validator before rendering begins. ESLint (eslint-config-canonical) and TypeScript strict mode enforce style and type safety, and GitHub Actions CI runs build, lint, and test across Node 10/12/14 on every push and pull request, uploading coverage to Coveralls.

What Makes It Unique Most terminal-table libraries either ignore ANSI escape codes and fullwidth characters when computing column widths (breaking alignment on colored or CJK content) or hand-roll config validation. table combines string-width- and ANSI-aware width measurement with schema-validated, ahead-of-time-compiled configuration, and adds spanning-cell support for merging content across rows and columns — a feature largely absent from comparable packages. The createStream API additionally allows a table to be built incrementally, redrawing only the trailing border on each write, which suits streaming or tailing use cases that a purely batch table(data) call cannot serve.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search