Table

Last updated on

A list field as rows, with a header that repeats on every page it continues onto.

Table is the one component whose header can outlive its own page: when a table's rows continue past a page break, the page plan copies its header onto the next page so the columns stay legible, and marks that copy data-keep-repeat so it is never confused with the header's one real place in the flow. A continuedLabel reads on that copy alone; a footer evaluates rows from the artifact's own definitions and stays with the table's last row; and a column's render can replace one cell's plain text with markup of its own, without changing how the row paginates.

Preview

Rendering live preview requires JavaScript.

Installation

npx shadcn@4 add @paradoc/table

Or, with the Paradoc CLI, which writes the namespace into components.json for you:

npx paradoc-cli add table

Installs to components/paradoc/table.tsx and brings along keep-together.

Usage

import { Table } from "@/components/paradoc/table";<Table  path="lineItems"  columns={[{ field: "description" }, { field: "amount", align: "right" }]}/>
PropTypeDefaultDescription
pathstring—Path to the list field this table reads its rows from.
columnsreadonly TableColumn[]—Column definitions: each names a list-item field, its header, width, and alignment.
id?string—Prefix for the header's and each row's pagination id; falls back to path.
className?string—Classes for the table's wrapping element.
continuedLabel?string—Shown on the repeated header when the table continues onto a later page, never on the first. Kept to one line.
footer?readonly TableFooterRow[]—Footer rows evaluated from the artifact's definitions; the page plan never opens a page on them without the table's last row.

Composition

A Table needs the same Document context every other component here does, and its path names a list field in the artifact — the same convention Field uses, just pointed at an array. Each columns entry names one field of the list's items and gets a Tailwind basis-* share of the row's width, so together they should sum to the whole row rather than leave columns floating loose.

Table renders as flex rows, not <table> markup, because the default PDF engine has no table support: a document using real table markup on screen could not be the same tree the PDF renders. What it brings along is Keep Together for both the header row and every data row — each is its own pagination unit — which is also what makes header repetition possible: the plan can place a copy of the header keep wherever a continued row needs one.

A Table normally lives inside a Section alongside the Fields around it, though nothing requires that — the Preview above renders one directly inside Document.

The header's size follows the document's typography token; the cells inherit the root's.

Variants

Table's columns each take a field, an optional header override, a width, and an align.

Compact

A two-column subset of the same lineItems table.

Rendering live preview requires JavaScript.

Left-aligned

Every column left-aligned, instead of the default's right-aligned numeric ones.

Rendering live preview requires JavaScript.

Custom headers

header overrides the artifact's own field labels.

Rendering live preview requires JavaScript.

Continued

continuedLabel shows on the repeated header once the table's rows carry it past a page break, and only there — the table's own, first header never shows it. This variant is the page's only one that self-wraps in Pages: every other table on this page fits one page, which is exactly where the label has nothing to show.

Rendering live preview requires JavaScript.

footer takes rows shaped like Totals's: a def, an optional label, and emphasis. Each is evaluated from the artifact's own definitions and printed as one more keep after the last row. When the footer does not fit on the last row's page, the last row moves to the next page with it, so the totals never print without a row above them.

Rendering live preview requires JavaScript.

Cell renderer

A column's render receives the cell's already-formatted text and the row it belongs to, and returns the markup to print instead. The row underneath still paginates as one unit.

Rendering live preview requires JavaScript.

On this page