# Paper

One sheet at the document's page geometry, and the fit-to-width hook.

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

`Paper` draws exactly one sheet, at the page geometry the document's tokens
name, and scales it to fit whatever frame it's given. It does not paginate:
content taller than one page just makes that one sheet taller, which is
exactly what [`Pages`](/components/pages) exists to prevent.

## Preview


```tsx
import { Document } from "@/components/asterdoc/document";
import { Field } from "@/components/asterdoc/field";
import { Paper } from "@/components/asterdoc/paper";
import { Section } from "@/components/asterdoc/section";
import { proposalForm } from "@/examples/proposal";
import { shortProposalData } from "@/examples/proposal-data";

export function PaperDemo() {
  return (
    <Paper>
      <Document artifact={proposalForm} data={shortProposalData} id="paper-demo">
        <Section id="customer" title="Prepared for" className="flex flex-col gap-1">
          <Field path="customer" label={false} />
          <Field path="customerAddress" label={false} />
        </Section>
      </Document>
    </Paper>
  );
}
```


## Installation


```bash
npx shadcn@4 add @asterdoc/paper
```


```bash
asterdoc add paper
```


Installs to components/asterdoc/paper.tsx.


## Usage


```tsx
import { Paper } from "@/components/asterdoc/paper";

<Paper className="w-full overflow-hidden bg-neutral-100 p-10">
  <Document artifact={proposalForm} data={shortProposalData}>
    <Field path="provider" />
  </Document>
</Paper>
```

| Prop | Type | Optional | Default | Description |
| --- | --- | --- | --- | --- |
| `className` | `string` | Yes |  | Classes for the outer frame that scales and centers the sheet. |
| `furniture` | `PageFurniture` | Yes |  | What every sheet carries outside the flow: a header, a footer, a stamp.
Drawn inside the document's margin, so the page count does not change. |
| `children` | `ReactNode` | No |  | Content drawn on the one sheet. |


## Composition

`Paper` reads its geometry — page size, margin — from the same document
tokens a [`Document`](/components/document) or [`Bundle`](/components/bundle)
resolves; it carries no tokens of its own. It draws whatever it is given, with
no [`Section`](/components/section) or particular layout required around the
content.

[`Pages`](/components/pages) uses `Paper`'s own `Sheet` internally for each
page it produces, so a preview that paginates never renders `Paper` directly
at the same time — `Paper` is for showing one sheet on its own, and `Pages`
is for showing however many a document's content actually needs.

`useFitToWidth`, the hook behind the scaling, is exported alongside `Paper`
for a caller that needs the same fit-to-frame behavior without the sheet
markup itself.

### Page furniture

`furniture` is what the sheet carries outside the flow: a `header` band, a
`footer` band, and a `stamp` behind the content — the same object
[`Pages`](/components/pages) takes and the same object
`renderPdf(element, { plan, furniture })` from
[`@asterdoc/react-pdf`](/sdk/react-pdf) takes. Each band is drawn inside the margin the
document declares, so it never moves the content; a band taller than that
margin fails by name rather than printing over the first line.

```tsx
<Paper furniture={{ header: <span>Northwind Partners LLP</span>, footer: <PageNumber /> }}>
  {document}
</Paper>
```

One sheet is page 1 of 1, so a [`PageNumber`](/components/page-number) drawn
here says so.

## Variants

`Paper` takes an optional `className` for its outer frame, `furniture`, and
`children`.

### Minimal content

`Paper` draws whatever it is given, with no `Section` or layout required
around it.


```tsx
import { Document } from "@/components/asterdoc/document";
import { Field } from "@/components/asterdoc/field";
import { Paper } from "@/components/asterdoc/paper";
import { proposalForm } from "@/examples/proposal";
import { shortProposalData } from "@/examples/proposal-data";

export function PaperVariantMinimalContent() {
  return (
    <Paper>
      <Document artifact={proposalForm} data={shortProposalData} id="paper-variant-minimal-content">
        <Field path="provider" />
      </Document>
    </Paper>
  );
}
```


### Custom frame

A custom `className` replaces the default frame's background and padding.


```tsx
import { Document } from "@/components/asterdoc/document";
import { Field } from "@/components/asterdoc/field";
import { Paper } from "@/components/asterdoc/paper";
import { proposalForm } from "@/examples/proposal";
import { shortProposalData } from "@/examples/proposal-data";

export function PaperVariantCustomFrame() {
  return (
    <Paper className="w-full overflow-hidden bg-neutral-100 p-10">
      <Document artifact={proposalForm} data={shortProposalData} id="paper-variant-custom-frame">
        <Field path="provider" />
      </Document>
    </Paper>
  );
}
```


### Overflowing content

`Paper` never paginates, so content taller than one page — a longer
proposal's line items — simply grows the one sheet past its normal height
instead of continuing onto a second sheet the way `Pages` would.


```tsx
import { Document } from "@/components/asterdoc/document";
import { Paper } from "@/components/asterdoc/paper";
import { Section } from "@/components/asterdoc/section";
import { Table } from "@/components/asterdoc/table";
import { proposalForm } from "@/examples/proposal";
import { overflowProposalData } from "@/examples/proposal-data";

export function PaperVariantOverflowingContent() {
  return (
    <Paper>
      <Document artifact={proposalForm} data={overflowProposalData} id="paper-variant-overflowing-content">
        <Section id="line-items" title="Scope and pricing" className="flex flex-col gap-3">
          <Table
            path="lineItems"
            id="line-items"
            columns={[
              { field: "description", width: "basis-1/2" },
              { field: "amount", width: "basis-1/6", align: "right" },
            ]}
          />
        </Section>
      </Document>
    </Paper>
  );
}
```
