Ink Web

Table

A table component with rounded box-drawing borders, column alignment, per-cell styling, and footer rows. Supports a simple "pass an array" API and an advanced "explicit columns + rows" API.

Terminal

Installation

npx shadcn@latest add https://raw.githubusercontent.com/cjroth/ink-web/main/packages/ink-ui/registry/table.json
npx shadcn@latest add https://raw.githubusercontent.com/cjroth/ink-web/main/packages/ink-ui/registry/table.json
pnpm dlx shadcn@latest add https://raw.githubusercontent.com/cjroth/ink-web/main/packages/ink-ui/registry/table.json
bunx shadcn@latest add https://raw.githubusercontent.com/cjroth/ink-web/main/packages/ink-ui/registry/table.json

Usage

app/page.tsx
"use client";

import dynamic from "next/dynamic";

const Terminal = dynamic(() => import("./terminal"), {
  ssr: false,
});

export default function Home() {
  return <Terminal />;
}
app/terminal.tsx
"use client";

import { Box } from "ink";
import { InkXterm } from "ink-web";
import { Table } from '@/components/ui/table'
import "ink-web/css";
import "@xterm/xterm/css/xterm.css";

const data = [
  { name: 'Alice', age: 30, city: 'NYC' },
  { name: 'Bob', age: 25, city: 'LA' },
  { name: 'Charlie', age: 35, city: 'Chicago' },
];

export default function Terminal() {
  return (
    <InkXterm focus>
      <Box flexDirection="column">
        <Table data={data} />
      </Box>
    </InkXterm>
  )
}

Props

The Table component accepts either simple or advanced props:

Simple mode

Pass an array of objects and the table auto-generates columns from the keys.

PropTypeDefaultDescription
dataT[]requiredArray of objects to display as rows
columns(keyof T)[]all keysWhich fields to show, and in what order
paddingnumber1Cell padding (characters)
maxHeaderWidthnumberunlimitedMax header width before truncating with

Advanced mode

Define columns and rows explicitly with per-cell styling.

PropTypeDefaultDescription
columnsColumn[]requiredColumn definitions
rowsCell[][]requiredArray of rows (each row is an array of cells)
footerRowsCell[][][]Footer rows displayed below a separator
paddingnumber1Cell padding (characters)
maxHeaderWidthnumber8Max header width before truncating with

Column

PropTypeDefaultDescription
headerstringrequiredColumn header text
widthnumberautoFixed column width
minWidthnumberMinimum column width
align'left' | 'right''left'Text alignment
headerColorstringColor for the header text

Cell

PropTypeDefaultDescription
textstringrequiredCell text (also used for width calculation)
colorstringText color
boldbooleanBold text
dimColorbooleanDimmed text
nodeReactNodeCustom render node (overrides text display)

Examples

Basic table

const data = [
  { name: 'Alice', age: 30, city: 'NYC' },
  { name: 'Bob', age: 25, city: 'LA' },
];

<Table data={data} />

Column selection

const data = [
  { id: 1, name: 'Alice', email: 'alice@example.com', age: 30 },
  { id: 2, name: 'Bob', email: 'bob@example.com', age: 25 },
];

<Table data={data} columns={['name', 'email']} />

Right-aligned numbers

<Table
  columns={[
    { header: 'Item' },
    { header: 'Price', align: 'right' },
  ]}
  rows={[
    [{ text: 'Widget' }, { text: '$10.00' }],
    [{ text: 'Gadget' }, { text: '$25.00' }],
  ]}
/>

Per-cell colors

<Table
  columns={[
    { header: 'Status', headerColor: 'cyan' },
    { header: 'Count', align: 'right' },
  ]}
  rows={[
    [{ text: 'Passing', color: 'green' }, { text: '42' }],
    [{ text: 'Failing', color: 'red' }, { text: '3' }],
    [{ text: 'Skipped', dimColor: true }, { text: '7' }],
  ]}
/>
<Table
  columns={[
    { header: 'Item' },
    { header: 'Price', align: 'right' },
  ]}
  rows={[
    [{ text: 'Widget' }, { text: '$10.00' }],
    [{ text: 'Gadget' }, { text: '$25.00' }],
  ]}
  footerRows={[
    [{ text: 'Total', bold: true }, { text: '$35.00', bold: true }],
  ]}
/>

Custom ReactNode cells

import { Text } from 'ink'

<Table
  columns={[
    { header: 'Task' },
    { header: 'Progress' },
  ]}
  rows={[
    [
      { text: 'Build' },
      { text: '████░░░░', node: <Text color="green">████░░░░</Text> },
    ],
    [
      { text: 'Test' },
      { text: '██████░░', node: <Text color="cyan">██████░░</Text> },
    ],
  ]}
/>

Output Format

╭─────────┬─────┬─────────╮
│ name    │ age │ city    │
├─────────┼─────┼─────────┤
│ Alice   │ 30  │ NYC     │
│ Bob     │ 25  │ LA      │
│ Charlie │ 35  │ Chicago │
╰─────────┴─────┴─────────╯

On this page