markdown-table

Turns arrays of strings into aligned GitHub-flavored markdown tables with configurable padding and column alignment.

Library
npm
v3.0.4
297stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
36/100Needs Attention
Development Activity0
Maintenance20
Community44
Maturity60
Momentum20

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
63/100Good
Architecture78
Code Quality92
Innovation28
Learning Curve55

markdown-table is a lightweight, dependency-free JavaScript utility from unified/remark ecosystem author Titus Wormer that converts a two-dimensional array of strings into a properly formatted GitHub Flavored Markdown (GFM) table. It handles column alignment (left, right, or center), delimiter padding, and serialization of primitives like numbers, booleans, null, and undefined, so callers don’t have to hand-roll ASCII table formatting logic themselves.

Unlike a full markdown processor, it doesn’t parse or escape content — it’s intentionally scoped to just the table-generation step, making it a natural building block for CLI tools, documentation generators, changelog scripts, and reporting tools that need to emit readable markdown output. For projects that need a complete markdown AST pipeline, the author recommends pairing mdast-util-to-markdown with mdast-util-gfm instead.

What You Get

  • A single markdownTable(table, options) function with zero runtime dependencies
  • Per-column left/center/right alignment via a simple ‘l’/‘c’/‘r’ string or array
  • Automatic delimiter-column alignment so table source reads cleanly, with an option to disable it for staggered output
  • A custom stringLength hook for correctly aligning columns containing full-width characters or emoji
  • Full TypeScript type definitions generated from JSDoc, including the exported Options type

Common Use Cases

  • Generating changelog or release-note tables from git/CI data in a build script
  • Rendering tabular query results as markdown inside a CLI tool or chat bot
  • Building documentation generators that emit GFM tables from structured data (API references, config option tables)
  • Formatting comparison or benchmark output in a README or PR comment

Under The Hood

Architecture The package is a single-file, single-function library (index.js, ~394 lines including heavy JSDoc): one exported markdownTable(table, options) runs three sequential passes over the input — building a cell/size matrix per row, computing a per-column alignment code, splicing in a synthesized alignment-delimiter row, then a final render loop that assembles each output line while respecting padding, delimiter-start/end, and alignDelimiters settings — backed by two small private helpers (serialize for value coercion, toAlignment for mapping align characters to codes). There is no I/O, no async, no class hierarchy, and no external dependency; the design deliberately returns a plain string rather than an AST, so the only real breaking-change surface is the documented Options shape.

Tech Stack Pure vanilla JavaScript targeting ES2020/Node 14.14+ and 16+, published ESM-only ("type": "module") with zero runtime dependencies. Types come from JSDoc compiled via TypeScript’s checkJs/emitDeclarationOnly into .d.ts/.d.ts.map files — no bundler or build framework, the shipped artifact is the raw index.js plus generated declarations. Dev tooling includes xo (an ESLint preset) and prettier for linting/formatting, remark-cli with remark-preset-wooorm for linting the README itself, c8 for coverage and type-coverage for strict type-coverage enforcement, and Node’s built-in node:test runner with node:assert/strict for tests. CI is a single GitHub Actions workflow matrix-testing the current and an older LTS Node release, uploading coverage to Codecov.

Code Quality The test suite (test.js, 337 lines) uses the native Node test runner to exercise the full public API, every alignment/padding/delimiter option, primitive serialization edge cases (numbers, booleans, null, undefined, arrays), and irregular row lengths. Both c8 --check-coverage (100% line coverage) and type-coverage (100% strict type coverage) are hard CI gates rather than aspirational targets. Error handling is minimal because the function has few failure modes, favoring defensive defaults (settings.align || [], a defaultStringLength fallback) over thrown exceptions. Naming and formatting are enforced consistently through the xo/prettier config embedded in package.json, and the whole module is strictly typed with exactOptionalPropertyTypes enabled.

API Design The public surface is intentionally tiny: one function, one options object, no classes or builder pattern to learn. Defaults favor the common case (left-aligned, padded, delimiter-wrapped tables) while every formatting toggle (align, padding, delimiterStart, delimiterEnd, alignDelimiters, stringLength) is opt-in and independently documented with before/after markdown examples in the README, which keeps the getting-started boilerplate to a single import and function call.

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