Tablemark
Generate markdown tables from JSON data.
Install / Use
/learn @haltcase/TablemarkREADME
tablemark ·

Generate markdown tables from JSON data.
Render arrays of objects as markdown tables, with configurable fancy output.
- Rename table headers and transform cell content
- Align columns to the left, center, or right (all columns or per column)
- Customize text casing for column headers (using [
change-case]) - Auto-detect and handle ANSI styles and Unicode characters
- Wrap or truncate long cell contents or strip line breaks
Installation
pnpm add tablemark
# or
npm install tablemark
# or
yarn add tablemark
# or
bun add tablemark
Usage
import { tablemark } from "tablemark";
tablemark([
{ name: "Bob", age: 21, isCool: false },
{ name: "Sarah", age: 22, isCool: true },
{ name: "Lee", age: 23, isCool: true }
]);
// | Name | Age | Is cool |
// | :---- | :---- | :------ |
// | Bob | 21 | false |
// | Sarah | 22 | true |
// | Lee | 23 | true |
... displays as:
<!-- prettier-ignore-start -->| Name | Age | Is cool | | :---- | :---- | :------ | | Bob | 21 | false | | Sarah | 22 | true | | Lee | 23 | true |
<!-- prettier-ignore-end -->API
tablemark (input: InputData, options?: TablemarkOptions): string
Arguments
-
InputDatainput: the data to table-ify as an array or iterable of objects- Note that nested objects are not supported. Use
options.toCellTextto customize how nested objects and other non-string values are output.
- Note that nested objects are not supported. Use
-
TablemarkOptionsoptions:| key | type | default | description | | :----------------------: | :------------------------------------------: | :--------------: | -------------------------------------------------------------------------------------------------- | |
align|"left" \| "center" \| "right"|"left"| Horizontal alignment to use for all columns. | |columns|Array<string \| ColumnDescriptor>| - | Array of column descriptors. | |countAnsiEscapeCodes|boolean|false| Whether to count ANSI escape codes when calculating string width. | |headerCase|"preserve" \| ...|"sentenceCase"| Casing to use for headers derived from input object keys (read more). | |lineBreakStrategy|"preserve" \| "strip" \| "truncate"|"preserve"| What to do when cell content contains line breaks. | |lineEnding|string|"\n"| String used at end-of-line. | |maxWidth|number|Infinity| Wrap cell text at this length. | |overflowStrategy|"wrap" \| "truncateStart" \| "truncateEnd"|"wrap"| How to handle overflowing text in cells. | |overflowHeaderStrategy|"wrap" \| "truncateStart" \| "truncateEnd"|"wrap"| How to handle overflowing text in header cells. | |padHeaderSeparator|boolean|true| Whether to pad gutters of the header separator (alignment) row. | |toCellText|({ key, value }) => string| - | Provide a custom cell value transform function. | |toHeaderTitle|({ key, title }) => string| - | Provide a custom header title transform function. | |unknownKeyStrategy|"ignore" \| "throw"|"ignore"| How to handle unknown keys found in objects. | |textHandlingStrategy|"auto" \| "advanced"|basic|"auto"| Control support for ANSI styles or Unicode characters (read more). | |wrapWithGutters|boolean|false| Add sides (\| <content> \|) to wrapped rows. |
Returns
string: the resulting markdown formatted table
If input is an empty array, an empty string is returned.
Throws
TypeError: when input is not iterable (e.g., an array)<br />
TypeError: when an unknown column alignment option is provided<br />
RangeError: when config.unknownKeyStrategy === "throw" and an unknown key in an object is encountered
[!NOTE] The keys of the first encountered object are used for the table's headers. By default, any other keys from successive objects will be ignored, excluding those columns from the table. You can customize this behavior to make this raise an error by using
config.unknownKeyStrategy.
options.align
Set the horizontal alignment for all columns. Accepts "left", "center", or "right".
tablemark(
[
{ name: "Bob", age: 21 },
{ name: "Sarah", age: 22 }
],
{ align: "center" }
);
// | Name | Age |
// | :---: | :-: |
// | Bob | 21 |
// | Sarah | 22 |
options.columns
Describe the columns of the table. Each column can be a simple string to rename the column or an object with properties to further customize the column's behavior. The following properties are available and will override behavior specified elsewhere in options:
name: Name of the column used as the title in the header row.align: Horizontal alignment of the column content.maxWidth: Maximum content width of this column.overflowHeaderStrategy: How to handle overflowing text in header cells. Defaults to"wrap".overflowStrategy: How to handle overflowing text in this column. Defaults to the rootoverflowStrategy.textHandlingStrategy: How to handle text in this column. Defaults to the roottextHandlingStrategy.width: Fixed display width for the column, overriding both the root- and column-levelmaxWidthsetting.
tablemark(
[
{ name: "Bob", age: 21, isCool: false },
{ name: "Sarah", age: 22, isCool: true },
{ name: "Lee", age: 23, isCool: true }
],
{
columns: [
"first name",
{ name: "how old", align: "center" },
"are they cool"
]
}
);
// | first name | how old | are they cool |
// | :--------- | :-----: | :------------ |
// | Bob | 21 | false |
// | Sarah | 22 | true |
// | Lee | 23 | true |
... displays as:
<!-- prettier-ignore-start -->| first name | how old | are they cool | | :--------- | :-----: | :------------ | | Bob | 21 | false | | Sarah | 22 | true | | Lee | 23 | true |
<!-- prettier-ignore-end -->options.countAnsiEscapeCodes
Control whether to count ANSI escape codes when calculating string width. The default is false, meaning ANSI codes are ignored. Setting this to true is useful when the output is not intended for a terminal, such as when generating a markdown table for an example in a README file.
const data = [
{ text: "\u001B[31mRed\u001B[0m", note: "Normal text" },
{ text: "\u001B[32mGreen\u001B[0m", note: "More text" }
];
tablemark(data, { countAnsiEscapeCodes: false });
// | Text | Note |
// | :---- | :---------- |
// | [31mRed[0m | Normal text |
// | [32mGreen[0m | More text |
tablemark(data, { countAnsiEscapeCodes: true });
// | Text | Note |
// | :------------- | :---------- |
// | [31mRed[0m | Normal text |
// | [32mGreen[0m | More text |
options.headerCase
Control the casing of headers derived from input object keys. The default is "sentenceCase". The options are:
"preserve": Keep the original case"camelCase": Example: twoWords"capitalCase": Example: Two Words"constantCase": Example: TWO_WORDS"dotCase": Example: two.words"kebabCase": Example: two-words"noCase": Example: two words"pascalCase": Example: TwoWords"pascalSnakeCase": Example: Two_Words"pathCase": Example: two/words"sentenceCase": Example: Two words"snakeCase": Example: two_words"trainCase": Example: Two-Words
tablemark([{ first_name: "Bob", last_name: "Smith" }], {
headerCase: "constantCase"
});
// | FIRST_NAME | LAST_NAME |
// | :--------- | :-------- |
// | Bob | Smith |
options.lineBreakStrategy
Specify how to handle line breaks in cell content. The options are:
"preserve"(default): Keep line breaks"strip": Replace line breaks with spaces"truncate": Trim content
Related Skills
node-connect
345.4kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
104.6kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
Writing Hookify Rules
104.6kThis skill should be used when the user asks to "create a hookify rule", "write a hook rule", "configure hookify", "add a hookify rule", or needs guidance on hookify rule syntax and patterns.
review-duplication
100.0kUse this skill during code reviews to proactively investigate the codebase for duplicated functionality, reinvented wheels, or failure to reuse existing project best practices and shared utilities.
