tbl-md
v0.5.0
Published
A readable table format for Markdown: key-based tables in a fenced tbl block, with lossless conversion to and from GFM tables
Readme
tbl-md
A readable table format for Markdown. A tbl block is a table in a fenced code block with short keys, one cell per line:
```tbl
model: Model
price: Price
note: Note
--
m: Opus
p: $15
n: Good for research.
Second line of the same cell.
--
m: Haiku
p: $1
```The first record is the header. It maps each key to a column title. A line -- starts the next row. In a row, write the shortest unique prefix of the key, mostly one letter, from the first row on. Then the cell texts of a row start at the same column. The full key is also valid. A missing key is an empty cell. The full format is in docs/format.md.
Why
A GFM pipe table is hard to read and to change as plain text. One long cell pushes all columns apart, and a pipe or a line break in a cell needs an escape. Humans and agents read Markdown mostly as text, so they suffer from it in each edit.
tbl-md has one goal: humans change tables in Markdown with no frustration. A machine reads any form, so each rule of the format serves the human who edits the text.
The switch is reversible. tbl-md convert --to gfm converts each tbl block back to a GFM table, and the file then renders the same. A corpus of real tables from other projects tests the round trip.
The format comes from a survey of readable table formats. No established format had a header record with short keys and a maintained TypeScript parser. A tbl block is unrelated to the troff preprocessor tbl and to the tbl- cell options of Quarto.
Install
npm install tbl-mdOr run the CLI with no install:
npx tbl-md lint README.md
bunx tbl-md lint README.mdThe package is ESM only. It needs Node 22 or later, or Bun. It has type declarations for TypeScript.
Use
CLI
tbl-md lint fails on a GFM pipe table and on an invalid tbl block. It names the file and the line of each problem:
docs/a.md:12:1: This is a GFM pipe table. Write it as a tbl block, for example with `tbl-md convert`. (gfm-table)
1 error and 0 warnings.tbl-md convert converts the GFM tables of each file to tbl blocks, in place. With --to gfm, it converts back:
tbl-md convert docs/*.md
tbl-md convert --to gfm docs/*.mdThe options, the configuration file .tbl-md.json, and a pre-commit hook are in docs/cli.md.
Library
import { convert, lint, parse, render } from "tbl-md";
const result = convert("| A |\n| --- |\n| x |\n", { to: "tbl" });
if (result.ok) console.log(result.output);The library can also parse a tbl block, render its canonical form, and lint a Markdown text. Each export is in docs/api.md.
markdown-it plugin
The plugin renders each tbl block as an HTML table, in each host that uses markdown-it, such as Discourse:
import markdownit from "markdown-it";
import tblPlugin from "tbl-md/markdown-it";
const md = markdownit().use(tblPlugin);The attribute mapping, the hook attributes, and the single script file for hosts with no ES modules are in docs/markdown-it.md.
How to write a table
- The first record is the header. Each line is
key: Title. A key has lower-case letters, digits,_, and-. The order of the lines is the column order. - A line
--starts the next row. - In a row, a line
key: textstarts a cell. Write the shortest unique prefix of the key, mostly one letter, from the first row on:m:formodel:. The full key is also valid. A missing key is an empty cell. - Each other line continues the cell above, so a cell can have many lines.
- Cell text is inline Markdown, as in a GFM cell. A pipe needs no escape. If a text line looks like a key line or like
--, add one backslash:hint\: text. - An attribute block on its own line describes a column, a row, or a cell, for example
{align=right}after a header key line. The syntax is the one of Pandoc and djot:#id,.class, andkey=value.
tbl-md lint names the line of each error. docs/format.md has the full rules.
Documentation
- docs/format.md: the
tblformat. It is the contract of the package. - docs/cli.md: the CLI, its configuration file, and the pre-commit hook.
- docs/api.md: the library API and the problem codes of the lint.
- docs/markdown-it.md: the markdown-it plugin.
- docs/known-gaps.md: the known gaps.
- docs/spec.md: the goal, the principles, and the decisions of each version.
- skills/tbl-md/SKILL.md: an Agent Skill that tells a coding agent to write each table as a
tblblock. Copy or link the folderskills/tbl-mdinto the skills folder of your agent, for example~/.claude/skills/. - CHANGELOG.md: the changes of each release.
- CONTRIBUTING.md: development, the corpus test, and the release.
The package holds the user docs and the skill too, in node_modules/tbl-md/docs/ and node_modules/tbl-md/skills/.
Status and license
Work in progress. The library, the markdown-it plugin, and the CLI exist. The package is on npm as tbl-md, with provenance. Before 1.0.0, a breaking change of the format gives a new minor version. docs/known-gaps.md lists what does not work yet.
The license is MIT, see LICENSE.
