Description
Produces a string that represents array data in a text table.
Table alternatives and similar modules
Based on the "Text" category.
Alternatively, view Table alternatives based on common mentions on social networks and blogs.
-
StegCloak
Hide secrets with invisible characters in plain text securely using passwords π§π»ββοΈβ -
i18n-node
Lightweight simple translation module for node.js / express.js with dynamic json storage. Uses common __('...') syntax in app and templates. -
string-length
Get the real length of a string - by correctly counting astral symbols and ignoring ansi escape codes
CodeRabbit: AI Code Reviews for Developers

* Code Quality Rankings and insights are calculated and provided by Lumnify.
They vary from L1 to L5 with "L5" being the highest.
Do you think we are missing an alternative of Table or a related project?
README
Table
Produces a string that represents array data in a text table.
[Demo of table displaying a list of missions to the Moon.](./.README/demo.png)
Features
- Works with strings containing fullwidth characters.
- Works with strings containing ANSI escape codes.
- Configurable border characters.
- Configurable content alignment per column.
- Configurable content padding per column.
- Configurable column width.
- Text wrapping.
Install
npm install table
Usage
import { table } from 'table';
// Using commonjs?
// const { table } = require('table');
const data = [
['0A', '0B', '0C'],
['1A', '1B', '1C'],
['2A', '2B', '2C']
];
console.log(table(data));
ββββββ€βββββ€βββββ
β 0A β 0B β 0C β
ββββββΌβββββΌβββββ’
β 1A β 1B β 1C β
ββββββΌβββββΌβββββ’
β 2A β 2B β 2C β
ββββββ§βββββ§βββββ
API
table
Returns the string in the table format
Parameters:
data: The data to display
- Type:
any[][]
- Required:
true
- Type:
config: Table configuration
- Type:
object
- Required:
false
- Type:
config.border
Type: { [type: string]: string }
\
Default: honeywell
template
Custom borders. The keys are any of:
topLeft
,topRight
,topBody
,topJoin
bottomLeft
,bottomRight
,bottomBody
,bottomJoin
joinLeft
,joinRight
,joinBody
,joinJoin
bodyLeft
,bodyRight
,bodyJoin
headerJoin
const data = [
['0A', '0B', '0C'],
['1A', '1B', '1C'],
['2A', '2B', '2C']
];
const config = {
border: {
topBody: `β`,
topJoin: `β¬`,
topLeft: `β`,
topRight: `β`,
bottomBody: `β`,
bottomJoin: `β΄`,
bottomLeft: `β`,
bottomRight: `β`,
bodyLeft: `β`,
bodyRight: `β`,
bodyJoin: `β`,
joinBody: `β`,
joinLeft: `β`,
joinRight: `β€`,
joinJoin: `βΌ`
}
};
console.log(table(data, config));
ββββββ¬βββββ¬βββββ
β 0A β 0B β 0C β
ββββββΌβββββΌβββββ€
β 1A β 1B β 1C β
ββββββΌβββββΌβββββ€
β 2A β 2B β 2C β
ββββββ΄βββββ΄βββββ
config.drawVerticalLine
Type: (lineIndex: number, columnCount: number) => boolean
\
Default: () => true
It is used to tell whether to draw a vertical line. This callback is called for each vertical border of the table.
If the table has n
columns, then the index
parameter is alternatively received all numbers in range [0, n]
inclusively.
const data = [
['0A', '0B', '0C'],
['1A', '1B', '1C'],
['2A', '2B', '2C'],
['3A', '3B', '3C'],
['4A', '4B', '4C']
];
const config = {
drawVerticalLine: (lineIndex, columnCount) => {
return lineIndex === 0 || lineIndex === columnCount;
}
};
console.log(table(data, config));
ββββββββββββββ
β 0A 0B 0C β
ββββββββββββββ’
β 1A 1B 1C β
ββββββββββββββ’
β 2A 2B 2C β
ββββββββββββββ’
β 3A 3B 3C β
ββββββββββββββ’
β 4A 4B 4C β
ββββββββββββββ
config.drawHorizontalLine
Type: (lineIndex: number, rowCount: number) => boolean
\
Default: () => true
It is used to tell whether to draw a horizontal line. This callback is called for each horizontal border of the table.
If the table has n
rows, then the index
parameter is alternatively received all numbers in range [0, n]
inclusively.
If the table has n
rows and contains the header, then the range will be [0, n+1]
inclusively.
const data = [
['0A', '0B', '0C'],
['1A', '1B', '1C'],
['2A', '2B', '2C'],
['3A', '3B', '3C'],
['4A', '4B', '4C']
];
const config = {
drawHorizontalLine: (lineIndex, rowCount) => {
return lineIndex === 0 || lineIndex === 1 || lineIndex === rowCount - 1 || lineIndex === rowCount;
}
};
console.log(table(data, config));
ββββββ€βββββ€βββββ
β 0A β 0B β 0C β
ββββββΌβββββΌβββββ’
β 1A β 1B β 1C β
β 2A β 2B β 2C β
β 3A β 3B β 3C β
ββββββΌβββββΌβββββ’
β 4A β 4B β 4C β
ββββββ§βββββ§βββββ
config.singleLine
Type: boolean
\
Default: false
If true
, horizontal lines inside the table are not drawn. This option also overrides the config.drawHorizontalLine
if specified.
const data = [
['-rw-r--r--', '1', 'pandorym', 'staff', '1529', 'May 23 11:25', 'LICENSE'],
['-rw-r--r--', '1', 'pandorym', 'staff', '16327', 'May 23 11:58', 'README.md'],
['drwxr-xr-x', '76', 'pandorym', 'staff', '2432', 'May 23 12:02', 'dist'],
['drwxr-xr-x', '634', 'pandorym', 'staff', '20288', 'May 23 11:54', 'node_modules'],
['-rw-r--r--', '1,', 'pandorym', 'staff', '525688', 'May 23 11:52', 'package-lock.json'],
['-rw-r--r--@', '1', 'pandorym', 'staff', '2440', 'May 23 11:25', 'package.json'],
['drwxr-xr-x', '27', 'pandorym', 'staff', '864', 'May 23 11:25', 'src'],
['drwxr-xr-x', '20', 'pandorym', 'staff', '640', 'May 23 11:25', 'test'],
];
const config = {
singleLine: true
};
console.log(table(data, config));
βββββββββββββββ€ββββββ€βββββββββββ€ββββββββ€βββββββββ€βββββββββββββββ€ββββββββββββββββββββ
β -rw-r--r-- β 1 β pandorym β staff β 1529 β May 23 11:25 β LICENSE β
β -rw-r--r-- β 1 β pandorym β staff β 16327 β May 23 11:58 β README.md β
β drwxr-xr-x β 76 β pandorym β staff β 2432 β May 23 12:02 β dist β
β drwxr-xr-x β 634 β pandorym β staff β 20288 β May 23 11:54 β node_modules β
β -rw-r--r-- β 1, β pandorym β staff β 525688 β May 23 11:52 β package-lock.json β
β -rw-r--r--@ β 1 β pandorym β staff β 2440 β May 23 11:25 β package.json β
β drwxr-xr-x β 27 β pandorym β staff β 864 β May 23 11:25 β src β
β drwxr-xr-x β 20 β pandorym β staff β 640 β May 23 11:25 β test β
βββββββββββββββ§ββββββ§βββββββββββ§ββββββββ§βββββββββ§βββββββββββββββ§ββββββββββββββββββββ
config.columns
Type: Column[] | { [columnIndex: number]: Column }
Column specific configurations.
Type: number
\
Default: the maximum cell widths of the column
Column width (excluding the paddings).
const data = [
['0A', '0B', '0C'],
['1A', '1B', '1C'],
['2A', '2B', '2C']
];
const config = {
columns: {
1: { width: 10 }
}
};
console.log(table(data, config));
ββββββ€βββββββββββββ€βββββ
β 0A β 0B β 0C β
ββββββΌβββββββββββββΌβββββ’
β 1A β 1B β 1C β
ββββββΌβββββββββββββΌβββββ’
β 2A β 2B β 2C β
ββββββ§βββββββββββββ§βββββ
Type: 'center' | 'justify' | 'left' | 'right'
\
Default: 'left'
Cell content horizontal alignment
const data = [
['0A', '0B', '0C', '0D 0E 0F'],
['1A', '1B', '1C', '1D 1E 1F'],
['2A', '2B', '2C', '2D 2E 2F'],
];
const config = {
columnDefault: {
width: 10,
},
columns: [
{ alignment: 'left' },
{ alignment: 'center' },
{ alignment: 'right' },
{ alignment: 'justify' }
],
};
console.log(table(data, config));
ββββββββββββββ€βββββββββββββ€βββββββββββββ€βββββββββββββ
β 0A β 0B β 0C β 0D 0E 0F β
ββββββββββββββΌβββββββββββββΌβββββββββββββΌβββββββββββββ’
β 1A β 1B β 1C β 1D 1E 1F β
ββββββββββββββΌβββββββββββββΌβββββββββββββΌβββββββββββββ’
β 2A β 2B β 2C β 2D 2E 2F β
ββββββββββββββ§βββββββββββββ§βββββββββββββ§βββββββββββββ
Type: 'top' | 'middle' | 'bottom'
\
Default: 'top'
Cell content vertical alignment
const data = [
['A', 'B', 'C', 'DEF'],
];
const config = {
columnDefault: {
width: 1,
},
columns: [
{ verticalAlignment: 'top' },
{ verticalAlignment: 'middle' },
{ verticalAlignment: 'bottom' },
],
};
console.log(table(data, config));
βββββ€ββββ€ββββ€ββββ
β A β β β D β
β β B β β E β
β β β C β F β
βββββ§ββββ§ββββ§ββββ
Type: number
\
Default: 1
The number of whitespaces used to pad the content on the left.
Type: number
\
Default: 1
The number of whitespaces used to pad the content on the right.
The paddingLeft
and paddingRight
options do not count on the column width. So the column has width = 5
, paddingLeft = 2
and paddingRight = 2
will have the total width is 9
.
const data = [
['0A', 'AABBCC', '0C'],
['1A', '1B', '1C'],
['2A', '2B', '2C']
];
const config = {
columns: [
{
paddingLeft: 3
},
{
width: 2,
paddingRight: 3
}
]
};
console.log(table(data, config));
ββββββββ€βββββββ€βββββ
β 0A β AA β 0C β
β β BB β β
β β CC β β
ββββββββΌβββββββΌβββββ’
β 1A β 1B β 1C β
ββββββββΌβββββββΌβββββ’
β 2A β 2B β 2C β
ββββββββ§βββββββ§βββββ
Type: number
\
Default: Infinity
The number of characters is which the content will be truncated.
To handle a content that overflows the container width, table
package implements text wrapping. However, sometimes you may want to truncate content that is too long to be displayed in the table.
const data = [
['Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus pulvinar nibh sed mauris convallis dapibus. Nunc venenatis tempus nulla sit amet viverra.']
];
const config = {
columns: [
{
width: 20,
truncate: 100
}
]
};
console.log(table(data, config));
ββββββββββββββββββββββββ
β Lorem ipsum dolor si β
β t amet, consectetur β
β adipiscing elit. Pha β
β sellus pulvinar nibh β
β sed mauris convallβ¦ β
ββββββββββββββββββββββββ
Type: boolean
\
Default: false
The table
package implements auto text wrapping, i.e., text that has the width greater than the container width will be separated into multiple lines at the nearest space or one of the special characters: \|/_.,;-
.
When wrapWord
is false
:
const data = [
['Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus pulvinar nibh sed mauris convallis dapibus. Nunc venenatis tempus nulla sit amet viverra.']
];
const config = {
columns: [ { width: 20 } ]
};
console.log(table(data, config));
ββββββββββββββββββββββββ
β Lorem ipsum dolor si β
β t amet, consectetur β
β adipiscing elit. Pha β
β sellus pulvinar nibh β
β sed mauris convallis β
β dapibus. Nunc venena β
β tis tempus nulla sit β
β amet viverra. β
ββββββββββββββββββββββββ
When wrapWord
is true
:
ββββββββββββββββββββββββ
β Lorem ipsum dolor β
β sit amet, β
β consectetur β
β adipiscing elit. β
β Phasellus pulvinar β
β nibh sed mauris β
β convallis dapibus. β
β Nunc venenatis β
β tempus nulla sit β
β amet viverra. β
ββββββββββββββββββββββββ
config.columnDefault
Type: Column
\
Default: {}
The default configuration for all columns. Column-specific settings will overwrite the default values.
config.header
Type: object
Header configuration.
Deprecated in favor of the new spanning cells API.
The header configuration inherits the most of the column's, except:
content
{string}: the header content.width:
calculate based on the content width automatically.alignment:
center
be default.verticalAlignment:
is not supported.config.border.topJoin
will beconfig.border.topBody
for prettier.
const data = [
['0A', '0B', '0C'],
['1A', '1B', '1C'],
['2A', '2B', '2C'],
];
const config = {
columnDefault: {
width: 10,
},
header: {
alignment: 'center',
content: 'THE HEADER\nThis is the table about something',
},
}
console.log(table(data, config));
ββββββββββββββββββββββββββββββββββββββββ
β THE HEADER β
β This is the table about something β
ββββββββββββββ¬βββββββββββββ¬βββββββββββββ’
β 0A β 0B β 0C β
ββββββββββββββΌβββββββββββββΌβββββββββββββ’
β 1A β 1B β 1C β
ββββββββββββββΌβββββββββββββΌβββββββββββββ’
β 2A β 2B β 2C β
ββββββββββββββ§βββββββββββββ§βββββββββββββ
config.spanningCells
Type: SpanningCellConfig[]
Spanning cells configuration.
The configuration should be straightforward: just specify an array of minimal cell configurations including the position of top-left cell and the number of columns and/or rows will be expanded from it.
The content of overlap cells will be ignored to make the data
shape be consistent.
By default, the configuration of column that the top-left cell belongs to will be applied to the whole spanning cell, except:
- The
width
will be summed up of all spanning columns. - The
paddingRight
will be received from the right-most column intentionally.
Advances customized column-like styles can be configurable to each spanning cell to overwrite the default behavior.
const data = [
['Test Coverage Report', '', '', '', '', ''],
['Module', 'Component', 'Test Cases', 'Failures', 'Durations', 'Success Rate'],
['Services', 'User', '50', '30', '3m 7s', '60.0%'],
['', 'Payment', '100', '80', '7m 15s', '80.0%'],
['Subtotal', '', '150', '110', '10m 22s', '73.3%'],
['Controllers', 'User', '24', '18', '1m 30s', '75.0%'],
['', 'Payment', '30', '24', '50s', '80.0%'],
['Subtotal', '', '54', '42', '2m 20s', '77.8%'],
['Total', '', '204', '152', '12m 42s', '74.5%'],
];
const config = {
columns: [
{ alignment: 'center', width: 12 },
{ alignment: 'center', width: 10 },
{ alignment: 'right' },
{ alignment: 'right' },
{ alignment: 'right' },
{ alignment: 'right' }
],
spanningCells: [
{ col: 0, row: 0, colSpan: 6 },
{ col: 0, row: 2, rowSpan: 2, verticalAlignment: 'middle'},
{ col: 0, row: 4, colSpan: 2, alignment: 'right'},
{ col: 0, row: 5, rowSpan: 2, verticalAlignment: 'middle'},
{ col: 0, row: 7, colSpan: 2, alignment: 'right' },
{ col: 0, row: 8, colSpan: 2, alignment: 'right' }
],
};
console.log(table(data, config));
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Test Coverage Report β
ββββββββββββββββ¬βββββββββββββ¬βββββββββββββ¬βββββββββββ¬ββββββββββββ¬βββββββββββββββ’
β Module β Component β Test Cases β Failures β Durations β Success Rate β
ββββββββββββββββΌβββββββββββββΌβββββββββββββΌβββββββββββΌββββββββββββΌβββββββββββββββ’
β β User β 50 β 30 β 3m 7s β 60.0% β
β Services ββββββββββββββΌβββββββββββββΌβββββββββββΌββββββββββββΌβββββββββββββββ’
β β Payment β 100 β 80 β 7m 15s β 80.0% β
ββββββββββββββββ΄βββββββββββββΌβββββββββββββΌβββββββββββΌββββββββββββΌβββββββββββββββ’
β Subtotal β 150 β 110 β 10m 22s β 73.3% β
ββββββββββββββββ¬βββββββββββββΌβββββββββββββΌβββββββββββΌββββββββββββΌβββββββββββββββ’
β β User β 24 β 18 β 1m 30s β 75.0% β
β Controllers ββββββββββββββΌβββββββββββββΌβββββββββββΌββββββββββββΌβββββββββββββββ’
β β Payment β 30 β 24 β 50s β 80.0% β
ββββββββββββββββ΄βββββββββββββΌβββββββββββββΌβββββββββββΌββββββββββββΌβββββββββββββββ’
β Subtotal β 54 β 42 β 2m 20s β 77.8% β
βββββββββββββββββββββββββββββΌβββββββββββββΌβββββββββββΌββββββββββββΌβββββββββββββββ’
β Total β 204 β 152 β 12m 42s β 74.5% β
βββββββββββββββββββββββββββββ§βββββββββββββ§βββββββββββ§ββββββββββββ§βββββββββββββββ
createStream
table
package exports createStream
function used to draw a table and append rows.
Parameter:
- config: the same as
table
's, exceptconfig.columnDefault.width
andconfig.columnCount
must be provided.
import { createStream } from 'table';
const config = {
columnDefault: {
width: 50
},
columnCount: 1
};
const stream = createStream(config);
setInterval(() => {
stream.write([new Date()]);
}, 500);
[Streaming current date.](./.README/api/stream/streaming.gif)
table
package uses ANSI escape codes to overwrite the output of the last line when a new row is printed.
The underlying implementation is explained in this Stack Overflow answer.
Streaming supports all of the configuration properties and functionality of a static table (such as auto text wrapping, alignment and padding), e.g.
import { createStream } from 'table';
import _ from 'lodash';
const config = {
columnDefault: {
width: 50
},
columnCount: 3,
columns: [
{
width: 10,
alignment: 'right'
},
{ alignment: 'center' },
{ width: 10 }
]
};
const stream = createStream(config);
let i = 0;
setInterval(() => {
let random;
random = _.sample('abcdefghijklmnopqrstuvwxyz', _.random(1, 30)).join('');
stream.write([i++, new Date(), random]);
}, 500);
[Streaming random data.](./.README/api/stream/streaming-random.gif)
getBorderCharacters
Parameter:
- template
- Type:
'honeywell' | 'norc' | 'ramac' | 'void'
- Required:
true
- Type:
You can load one of the predefined border templates using getBorderCharacters
function.
import { table, getBorderCharacters } from 'table';
const data = [
['0A', '0B', '0C'],
['1A', '1B', '1C'],
['2A', '2B', '2C']
];
const config = {
border: getBorderCharacters(`name of the template`)
};
console.log(table(data, config));
# honeywell
ββββββ€βββββ€βββββ
β 0A β 0B β 0C β
ββββββΌβββββΌβββββ’
β 1A β 1B β 1C β
ββββββΌβββββΌβββββ’
β 2A β 2B β 2C β
ββββββ§βββββ§βββββ
# norc
ββββββ¬βββββ¬βββββ
β 0A β 0B β 0C β
ββββββΌβββββΌβββββ€
β 1A β 1B β 1C β
ββββββΌβββββΌβββββ€
β 2A β 2B β 2C β
ββββββ΄βββββ΄βββββ
# ramac (ASCII; for use in terminals that do not support Unicode characters)
+----+----+----+
| 0A | 0B | 0C |
|----|----|----|
| 1A | 1B | 1C |
|----|----|----|
| 2A | 2B | 2C |
+----+----+----+
# void (no borders; see "borderless table" section of the documentation)
0A 0B 0C
1A 1B 1C
2A 2B 2C
Raise an issue if you'd like to contribute a new border template.
Borderless Table
Simply using void
border character template creates a table with a lot of unnecessary spacing.
To create a more pleasant to the eye table, reset the padding and remove the joining rows, e.g.
const output = table(data, {
border: getBorderCharacters('void'),
columnDefault: {
paddingLeft: 0,
paddingRight: 1
},
drawHorizontalLine: () => false
}
);
console.log(output);
0A 0B 0C
1A 1B 1C
2A 2B 2C
*Note that all licence references and agreements mentioned in the Table README section above
are relevant to that project's source code only.