# Overview

Install the document components into your own project with the shadcn CLI

Canonical URL: https://docs.asterdoc.com/components/

A document composed in React is a tree of small components: a section, a field, a
table, a signature block. What each one renders is a design decision that belongs
to you, so they are not shipped as sealed exports. They are shipped as source, in
the [shadcn registry format](https://ui.shadcn.com/docs/registry): you install a
component, the file lands in your project, and from then on it is yours to edit.

What stays in `@asterdoc/react` is the part that is not a design decision — the
document, page, token and signing contexts, the page plan, the measuring pass,
the serializers that turn a value into the text a field prints. The installed
files import it from there. Editing a copied field changes how a field looks; it
cannot change how the document paginates or which paper it is drawn on.

See [Installation](/components/installation) for setup, once per project, and
[Typography](/components/typography) for the token that sets a document's type
scale and block spacing.

## The items

| Item                                                                      | What it is                                                                                                                      |
| ------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| [`document-styles`](https://docs.asterdoc.com/r/document-styles.json)     | Tailwind, the structural rules the components need, and every class the [typography](/components/typography) token can produce. |
| [`bundle`](/components/bundle)                                            | Groups the documents of one composition.                                                                                        |
| [`document`](/components/document)                                        | Binds one form artifact and its data to everything beneath it.                                                                  |
| [`field`](/components/field)                                              | One labelled value at a path into the artifact, printed by the artifact's serializers.                                          |
| [`image`](/components/image)                                              | A picture at a declared size, from its own bytes or from a source.                                                              |
| [`keep-together`](/components/keep-together)                              | The pagination unit. Content inside one is never split across a page break.                                                     |
| [`list`](/components/list)                                                | An ordered or unordered list whose markers are text, with every item its own pagination unit.                                   |
| [`page-break`](/components/page-break)                                    | Starts a new page at its position, occupying no height of its own.                                                              |
| [`page-number`](/components/page-number)                                  | The page being drawn and how many there are, for a document's page furniture.                                                   |
| [`pages`](/components/pages)                                              | Measures the document once and lays it out as paginated sheets.                                                                 |
| [`paper`](/components/paper)                                              | One sheet at the document's page geometry, and the fit-to-width hook.                                                           |
| [`part`](/components/part)                                                | One document of a packet, numbering its own pages and saying where it sits in the packet.                                       |
| [`party`](/components/party)                                              | One party of a declared role, with the organization, address, and contact fields beside it, as a block or inline.               |
| [`pdf-pages`](/components/pdf-pages)                                      | A PDF part of a packet, painted page by page, or a named attachment when it cannot be painted.                                  |
| [`qr-code`](/components/qr-code)                                          | An SVG QR code that links a document to a URL, with configurable size and colors.                                               |
| [`section`](/components/section)                                          | A titled container that collapses on pages holding none of its keeps.                                                           |
| [`signature`](/components/signature)                                      | A party's signing block, with the rule the seal measures a signature field from.                                                |
| [`table`](/components/table)                                              | A list field as rows, with a header that repeats on every page it continues onto.                                               |
| [`text`](/components/text)                                                | Static prose in a named role — heading, body, caption, or small — sized by the typography token.                                |
| [`totals`](/components/totals)                                            | The artifact's computed amounts, evaluated by `@asterdoc/core`.                                                                 |
| [`priced-line-items`](https://docs.asterdoc.com/r/priced-line-items.json) | Sample line-item arithmetic installed with the worked invoice and purchase-order blocks.                                        |

All 19 components link to a full reference page: a live preview,
installation, usage, the composition it was rendered from, and a few
alternate configurations. `document-styles` and `priced-line-items` link
straight to their registry JSON — they're supporting presets, not
components with their own page.

## The blocks

A block is a whole document rather than one component: an artifact, a
composition that binds it, and sample data to see it with.

| Item                                                        | What it is                                                                                                                                                                      |
| ----------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [`purchase-order`](/components/blocks/purchase-order)       | A purchase order: the artifact with its React layer, the composition, and a sample order that runs to three pages.                                                              |
| [`invoice`](/components/blocks/invoice)                     | An invoice nothing signs: the artifact with its React layer, the composition branded from its own tokens, and two samples — one page, and one whose table runs past two breaks. |
| [`engagement-letter`](/components/blocks/engagement-letter) | An engagement letter: the artifact with two signature slots, a composition whose scope of services is numbered prose clauses, and a sample that runs to two pages.              |
| [`vendor-packet`](/components/blocks/vendor-packet)         | A packet of three documents: the purchase order composed live, a filled W-9 painted from its PDF layer, and a certificate of insurance as an annex, whose bytes it ships.       |

```bash
asterdoc add purchase-order
```

The composition lands in `components/asterdoc/` beside the components; the
artifact and its data land in `artifacts/asterdoc/`, because they are not
components. `vendor-packet` brings `purchase-order` with it: the order is one of
the packet's parts.

The purchase order's sample runs to three pages, so its table continues across
two breaks. The repeated header on a continued page comes from the page plan:
you see it in the preview, and in a PDF rendered with the preview's plan passed
as hints. The engine paginating on its own does not copy one.

**`vendor-packet` needs `@asterdoc/essentials`**, and declares it. Nothing the
block ships imports it, but the packet's second part is the IRS W-9: filling and
sealing it needs that artifact. The block's sample carries the taxpayer's
values, not the form.

```tsx
import { w9 } from "@asterdoc/essentials";
import { vendorPacketData } from "@/artifacts/asterdoc/vendor-packet.data";

const parsed = w9.safeParseData(vendorPacketData.taxpayer);
if (!parsed.success) throw new Error("Invalid taxpayer data");
const draft = w9.fill(parsed.data);
const taxpayerPdf = await draft.render({ layer: "pdf" });
```

No resolver is passed: `@asterdoc/essentials` binds each artifact's bundled
resolver when it constructs the form, and every instance derived from it,
including `draft`, carries it.

The certificate of insurance is not yours to supply: the block installs it as
`vendor-packet.annex.ts`, a module of bytes, because a block installed into a
browser project has no engine to draw one with. The composition still takes both
PDFs as props.

The index of all of them is [`/r/registry.json`](https://docs.asterdoc.com/r/registry.json).

## For agents

`/r/registry.json` is machine-readable: `name`, `type`, `title`,
`description`, `dependencies`, and the files each item installs, with no page
to scrape. Fetch it to enumerate what is installable, then fetch
`/r/{name}.json` for one item's exact file list. Both are static JSON with no
auth.

Before rendering a newly authored or edited composition, run
`asterdoc check <composition-or-artifact-file>` — it walks the same tree the
default PDF path walks and reports every unsupported class, unresolved field
path, and missing image in one pass, without producing PDF bytes or needing a
browser. See [`asterdoc check`](/cli/commands/check) and
[`asterdoc add`](/cli/commands/add).

The [`asterdoc-react` agent skill](/ai/skills/asterdoc-react) packages this page's
content plus the component props, the pagination rule, the verified Tailwind
class subset, and the render and seal flow for an agent authoring a
composition end to end.

## Using them

```tsx
import { Document } from "@/components/asterdoc/document";
import { Field } from "@/components/asterdoc/field";
import { Pages } from "@/components/asterdoc/pages";
import { Section } from "@/components/asterdoc/section";

export function Proposal({ artifact, data }) {
  return (
    <Pages>
      <Document artifact={artifact} data={data}>
        <Section id="parties" title="Parties">
          <Field path="customer" />
          <Field path="issuedOn" />
        </Section>
      </Document>
    </Pages>
  );
}
```

`Field` names a path and prints nothing of its own: the label comes from the
artifact and the text comes from the serializer the field's type names. The same
tree renders to PDF through `@asterdoc/react-pdf`.

## How the registry is built

The items are generated from the component sources by `pnpm registry:build` in
the private `@asterdoc/components` workspace, never written by hand. The generator rewrites every import so
the file compiles where it is installed: a sibling item becomes
`@/components/asterdoc/<name>`, and anything else in the package becomes
`@asterdoc/react`, pinned to the public runtime version the item targets. A binding
the package does not export publicly, or an npm package the item does not
declare, fails the build rather than shipping a file you cannot compile, and the
emitted files are installed into a scratch project and type-checked on every
change.
