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.jsonnpx shadcn@latest add https://raw.githubusercontent.com/cjroth/ink-web/main/packages/ink-ui/registry/table.jsonpnpm dlx shadcn@latest add https://raw.githubusercontent.com/cjroth/ink-web/main/packages/ink-ui/registry/table.jsonbunx shadcn@latest add https://raw.githubusercontent.com/cjroth/ink-web/main/packages/ink-ui/registry/table.jsonUsage
"use client";
import dynamic from "next/dynamic";
const Terminal = dynamic(() => import("./terminal"), {
ssr: false,
});
export default function Home() {
return <Terminal />;
}"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.
| Prop | Type | Default | Description |
|---|---|---|---|
data | T[] | required | Array of objects to display as rows |
columns | (keyof T)[] | all keys | Which fields to show, and in what order |
padding | number | 1 | Cell padding (characters) |
maxHeaderWidth | number | unlimited | Max header width before truncating with … |
Advanced mode
Define columns and rows explicitly with per-cell styling.
| Prop | Type | Default | Description |
|---|---|---|---|
columns | Column[] | required | Column definitions |
rows | Cell[][] | required | Array of rows (each row is an array of cells) |
footerRows | Cell[][] | [] | Footer rows displayed below a separator |
padding | number | 1 | Cell padding (characters) |
maxHeaderWidth | number | 8 | Max header width before truncating with … |
Column
| Prop | Type | Default | Description |
|---|---|---|---|
header | string | required | Column header text |
width | number | auto | Fixed column width |
minWidth | number | — | Minimum column width |
align | 'left' | 'right' | 'left' | Text alignment |
headerColor | string | — | Color for the header text |
Cell
| Prop | Type | Default | Description |
|---|---|---|---|
text | string | required | Cell text (also used for width calculation) |
color | string | — | Text color |
bold | boolean | — | Bold text |
dimColor | boolean | — | Dimmed text |
node | ReactNode | — | Custom 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' }],
]}
/>Footer row
<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 │
╰─────────┴─────┴─────────╯