Render readable & responsive tables in the terminal

Overview

terminal-columns

Readable tables for the terminal.


Tables can be automatically responsive!

Features

  • Content wrapped to fit column width
  • Column widths auto, content-width, viewport percents & static values
  • Align left & right
  • Horizontal & vertical padding
  • Rows can overflow into multiple rows
  • Easy to make responsive tables

Try it out online

Support this project by ⭐️ starring and sharing it. Follow me to see what other cool projects I'm working on! ❤️

🚀 Install

npm i terminal-columns

🚦 Quick start

Render a table by passing table data into terminal-columns and writing it to stdout.

import terminalColumns from 'terminal-columns'

// Create table data
const tableData = [
    ['Cell A1', 'Cell B1', 'Cell C1'],
    ['Cell A2', 'Cell B2', 'Cell C2'],
    ['Cell A3', 'Cell B3', 'Cell C3']
]

// Render table
const tableString = terminalColumns(tableData)
console.log(tableString)

By default, the columns will be rendered with the auto width, which splits the available width with other auto columns. To configure the width of each column, pass them in as the second argument.

const tableString = terminalColumns(
    tableData,

    // Configure column widths
    [
        'content-width', // Use the width of the content
        '50%', // Fill 50% of viewport width
        'auto' // Fill remaining width
    ]
)

📖 Examples

Fixed width table

You can set a fixed width for each column by passing in a the number of columns.

However, note that this will wrap the row to the next line if the viewport width is smaller than the table width.

terminalColumns(
    tableData,
    [
        30,
        30,
        30
    ]
)

Fixed width table with no row-wrapping

You can change the row-wrapping behavior by telling terminal-columns to use a different viewport width via the stdoutColumns option. For example, passing in Infinity will trick it into thinking the table is never overflowing the viewport width.

terminalColumns(
    tableData,
    {
        stdoutColumns: Number.POSITIVE_INFINITY,
        columns: [
            30,
            30,
            30
        ]
    }
)

Padding

You can add padding to each column by setting paddingLeft, paddingRight, paddingTop, or paddingBottom on the column.

terminalColumns(
    tableData,
    [
        {
            paddingLeft: 2 // Pad the left side of the cell with 2 spaces
        },
        {
            paddingRight: 2 // Pad the right side of the cell with 2 spaces
        },
        {
            paddingTop: 2 // Pad the top of the cell with 2 lines
        },
        {
            paddingBottom: 2 // Pad the bottom of the cell with 2 lines
        }
    ]
)

Right align text

You can align the content of the column by setting align: 'right'.

terminalColumns(
    tableData,
    [
        {
            align: 'right'
        }
    ]
)

Responsive table with breakpoints function

Define breakpoints declaratively with the breakpoints function.

import terminalColumns, { breakpoints } from 'terminal-columns'

terminalColumns(
    tableData,
    breakpoints({
        // Large screens
        '>= 90': ['content-width', 'auto'],

        // Small screens
        '>= 25': ['100%', '100%'],

        // Tiny screens - remove responsiveness
        '>= 0': {
            columns: ['content-width', 'content-width'],
            stdoutColumns: Number.POSITIVE_INFINITY
        }
    })
)

Preprocess / Postprocess

Preprocessing and postprocessing can be used to modify the table data before it is rendered. It's primarily designed for formatting purposes and can be useful to style text in a declarative manner.

In this example, the first column spans the entire screen and is transformed to be uppercase on screens smaller than 80 columns.

terminalColumns(
    tableData,
    breakpoints({
        // Small screens
        '< 80': [
            {
                width: '100%',
                preprocess: text => text.toUpperCase()
            },
            '100%'
        ]
    })
)

Responsive table with custom function

You can make the table responsive by passing in a function that computes the column width allocation based on the detected viewport width.

For a working example, see this example.

terminalColumns(
    tableData,
    (stdoutColumns) => {
        /**
         * For large viewports
         * Split screen automatically
         */
        if (stdoutColumns > 100) {
            return [
                {
                    width: 'auto',
                    paddingRight: 1
                },
                {
                    width: 'auto'
                }
            ]
        }

        /**
         * For medium viewports
         * Break table row into two rows, and add vertical padding to create
         * a divider between rows
         */
        if (stdoutColumns > 30) {
            return [
                {
                    width: '100%'
                },
                {
                    width: '100%',
                    paddingBottom: 1
                }
            ]
        }

        /**
         * For viewports smaller than or equal to 30 columns
         * In this case, the screen is too small to render anything.
         * Simply remove responsiveness and assume the viewport width
         * is actually 1000 columns.
         */
        return {
            // Remove responsiveness
            stdoutColumns: 1000,
            columns: [
                {
                    width: 'content-width',
                    paddingRight: 1
                },
                {
                    width: 'content-width'
                }
            ]
        }
    }
)

⚙️ API

terminalColumns(tableData, options?)

Return type: string

Takes in table data and outputs a string that represents the table within the current terminal width (process.stdout.columns).

tableData

Type: string[][]

Required

A nested array where the first-level are "rows", and the second-level are "columns".

options

Type: OptionsObject | (stdoutColumns: number) => OptionsObject | ColumnMetasArray

Schema:

type Options = OptionsObject | OptionsFunction

type OptionsObject = ColumnMetasArray | {
    columns: ColumnMetasArray
    stdoutColumns?: number
}

type OptionsFunction = (stdoutColumns: number) => OptionsObject

type ColumnMetasArray = (ColumnWidth | ColumnMeta)[]

type ColumnWidth = number | 'content-width' | 'auto' | string

type ColumnMeta = {
    width: ColumnWidth
    paddingRight?: number
    paddingLeft?: number
    paddingTop?: number
    paddingBottom?: number
    align?: 'left' | 'right'
}

Options to define the column widths (default is auto) and the stdout columns to use.

stdoutColumns

Type: number

Default: process.stdout.columns

The number of columns in the terminal. Autodetected by default. This is used to calculate the max-width of the table and can be overriden to force a specific width.

columns

Type: Object

width

Type: number | 'content-width' | 'auto' | string

  • number: number of columns to span
  • 'content-width': The width of the content in the column
  • 'auto': Allocate the remaining width of the row to the column
  • string: Percentage of the viewport width to use (e.g. '50%')

For all of these values, the max width is stdoutColumns.

paddingLeft

Type: number

How many spaces to the left the column should have

paddingRight

Type: number

How many spaces to the right the column should have

paddingTop

Type: number

How many new lines to the top the column should have

paddingBottom

Type: number

How many new lines to the bottom the column should have

align

Type: 'left' | 'right'

Default: 'left'

Whether to align the text to the left or right.

preprocess

Type: (cellValue: string) => string

Function to preprocess the cell value before it is wrapped to the column width.

postprocess

Type: (line: string, lineNumber: number) => string

Function to postprocess the individual lines of a cell after it has been wrapped to the column width.

breakpoints(breakpointsMap)

A function to declaratively define breakpoints. Returns a function pass into terminal-columns.

breakpointsMap

Type: Record<string, Options>

An object mapping breakpoints to options. The key must be in the format: <operator> <stdout-columns>. For example, >= 90 will match if the terminal width is 90 or more.

You might also like...

Minimalistic configuration for TS to only extend JS with types. No TS features, no bundling. Readable maintainable code after compilation.

Minimalistic configuration for TS to only extend JS with types. No TS features, no bundling. Readable maintainable code after compilation.

ts-guideline Minimalistic configuration for TS to only extend JS with types. No TS-scpecific features, no bundling. Readable maintainable code after c

Dec 22, 2022

Wrap zod validation errors in user-friendly readable messages

zod-validation-error Wrap zod validation errors in user-friendly readable messages. Features User-friendly readable messages, configurable via options

Dec 23, 2022

Svelte component to display time distances in a human readable format.

Time Distance Display time distances in a human readable format. Based on date-fns Updates every 60 seconds View demo Usage Install package: pnpm i -D

Nov 2, 2022

Responsive Tabs is a jQuery plugin that provides responsive tab functionality.

Responsive Tabs is a jQuery plugin that provides responsive tab functionality. The tabs transform to an accordion when it reaches a CSS breakpoint. You can use this plugin as a solution for displaying tabs elegantly on desktop, tablet and mobile.

Dec 8, 2022

Portfolio page using React.js to render dynamic HTML

Meta-Portfolio Portfolio page using React.js to render dynamic HTML Version 1.0 Note You are important. Installation Instructions No installation nece

May 17, 2022

Websheetjs - Lightweight JS library to render website sections with data from Google Spreadsheets

websheet.js Render website sections with lazy-loaded data from Google Spreadsheets It's lightweight, fast, free and open-source ! See how it works, fu

Oct 4, 2022

Dokka plugin to render Mermaid graphics, from your code comments to your Dokka documentation.

Dokka plugin to render Mermaid graphics, from your code comments to your Dokka documentation.

Html Mermaid Dokka plugin Mermaid-Dokka MermaidJS 0.2.2 8.14.0 0.3.0 9.0.0 Step 1: install dependencies { dokkaPlugin("com.glureau:html-mermaid-dokk

Sep 16, 2022

A plugin for the Obsidian markdown note application, adding functionality to render markdown documents with multiple columns of text.

A plugin for the Obsidian markdown note application, adding functionality to render markdown documents with multiple columns of text.

Multi-Column Markdown Take your boring markdown document and add some columns to it! With Multi Column Markdown rather than limiting your document lay

Jan 2, 2023

Given a list of items, only render what's visible on the screen while allowing scrolling the whole list.

Solid Windowed Given a list of items, only render what's visible on the screen while allowing scrolling the whole list. A Solid component. See https:/

Dec 21, 2022
Comments
  • Label Data

    Label Data

    could we also export other data of the labels? Such as:

    • how many open issues in this repo has this label on it?
    • how many issues in total has this label on it?
    • when was the last issue created that has this label on it?

    I would need it to see how important/how much this label is still used in the repo.

    enhancement 
    opened by the-right-joyce 1
Releases(v1.4.1)
Owner
hiroki osame
I'm on a mission to open source my solutions 🚀
hiroki osame
An Obsidian plugin to paste Excel tables as Markdown tables in Obsidian editor.

Obsidian Excel to Markdown Table An Obsidian plugin to paste Excel tables as Markdown tables in Obsidian editor. Demo You can paste the copied Excel d

Ganessh Kumar 108 Jan 4, 2023
Engine render, fps and I/O on terminal.

typesgine-ascii - Game ASCII engine for terminal About | technologies | Features | Examples | Functions | License ?? About Typesgine is engine for cre

Gabriel Barros Feitosa Sá 3 Jun 10, 2022
Send encrypted and decrypted messages with verifiable keys and human readable names.

zooko-msg Encrypt and decrypt messages using AES with a preshared ECDH key generated using keys associated with Handshake names. I noticed that there

Publius Federalist 31 Jul 27, 2022
Convert JSON to human readable HTML

json.human.js: Json Formatting for Human Beings A small library to convert a JSON object into a human readable HTML representation that is easy to sty

Mariano Guerra 955 Dec 3, 2022
⏱ Simple Alpine.js plugin to display the human-readable distance between a date and now.

⏱ Alpine TimeAgo ⏱ An Alpine.js plugin to return the distance between a given date and now in words (like "3 months ago", "about 2 hours ago" or "in a

Marc Reichel 47 Dec 22, 2022
⛲ Sort import declarations into a pleasing and readable cascade.

⛲ eslint-plugin-cascading-imports This plugin allows to automatically enforce a visual "cascading" order for import declarations. Imports in each bloc

Florent 1 Jan 20, 2022
A compiled-away, type-safe, readable RegExp alternative

?? magic-regexp A compiled-away, type-safe, readable RegExp alternative ✨ Changelog ?? Documentation ▶️ Online playground Features Runtime is zero-dep

Daniel Roe 1.5k Jan 8, 2023
Enhanced interval features for Node.js, such as promisified interval and human readable time parsing.

Interval-next Interval-next is a package that extends Javascript's built-in setInterval() capabilities. You have a plain and promisified interval meth

Snowy 5 Jul 28, 2022
Library for readable and manageable Next.js middleware

?? Next Compose Middleware This is a library for building Next.js complex middleware declaratively. You can create highly readable and manageable midd

Ibuki Kaji 14 Dec 19, 2022
parses human-readable strings for JavaScript's Temporal API

?? temporal-parse What is the temporal-parse? Temporal is the next generation of JavaScript's standard Date API. It's currently proposed to TC39 (see:

Eser Ozvataf 22 Jan 2, 2023