

<Preview name="PreviewDefaultScenario" />

## Overview [#overview]

`Preview` is a composable shell for displaying prepared content in a panel,
dialog, or other constrained surface. Compose its fixed translucent header with
`Toolbar`, then render the appropriate content component inside
`Preview.Content`.

Cubitt owns the preview layout, presentation, read-only renderers, HTML
isolation, and PDF controls. Consumers own file loading, authorization, MIME
type detection, CSV parsing, document conversion, email attachment resolution,
remote-content approval, download actions, and error state. Pass content to
`Preview` only once it is ready to display.

## Usage [#usage]

```tsx
import { Preview } from "@tilt-legal/cubitt-components/preview";
import { Toolbar } from "@tilt-legal/cubitt-components/toolbar";
```

```tsx
<Preview aria-label="Attachment preview">
  <Preview.Header>
    <Toolbar>
      <Toolbar.Heading>
        <Toolbar.Title className="truncate text-base">
          {fileName}
        </Toolbar.Title>
      </Toolbar.Heading>
      <Toolbar.Actions>{actions}</Toolbar.Actions>
    </Toolbar>
  </Preview.Header>
  <Preview.Content>
    <Preview.Markdown content={markdown} />
  </Preview.Content>
</Preview>
```

## Examples [#examples]

### Markdown [#markdown]

Use `Preview.Markdown` for prepared Markdown content. It uses the Cubitt
`Editor` in read-only Markdown mode.

<Tabs items="[&#x22;Preview&#x22;, &#x22;Code&#x22;]">
  <Tab value="Preview">
    <Preview name="PreviewDefaultScenario" />
  </Tab>

  <Tab value="Code">
    ```tsx
    import { Preview } from "@tilt-legal/cubitt-components/preview";

    const markdown = `# Engagement summary

    The parties agreed to a **two-year engagement** beginning on 1 July 2026.`;

    <Preview.Content>
      <Preview.Markdown content={markdown} />
    </Preview.Content>;
    ```
  </Tab>
</Tabs>

### Plain Text [#plain-text]

Use `Preview.Text` for plain text. Blank lines become ordinary Markdown
paragraphs while the editor remains read-only.

<Tabs items="[&#x22;Preview&#x22;, &#x22;Code&#x22;]">
  <Tab value="Preview">
    <Preview name="PreviewPlainTextScenario" />
  </Tab>

  <Tab value="Code">
    ```tsx
    import { Preview } from "@tilt-legal/cubitt-components/preview";

    const transcript = `Interview transcript

    The witness confirmed that the meeting began at 9:30 am.`;

    <Preview.Content>
      <Preview.Text content={transcript} />
    </Preview.Content>;
    ```
  </Tab>
</Tabs>

### CSV [#csv]

Parse the CSV in the consuming application, then pass prepared columns and rows
to `Preview.Csv`. It renders the standard Cubitt `Table` and does not own
parsing, schema inference, sorting, or filtering.

<Tabs items="[&#x22;Preview&#x22;, &#x22;Code&#x22;]">
  <Tab value="Preview">
    <Preview name="PreviewCsvScenario" />
  </Tab>

  <Tab value="Code">
    ```tsx
    import { Preview } from "@tilt-legal/cubitt-components/preview";

    const columns = [
      { id: "date", label: "Date" },
      { id: "description", label: "Description" },
      { id: "amount", label: "Amount" },
    ];

    const rows = [
      {
        id: "entry-1",
        cells: {
          date: "2026-07-01",
          description: "Review engagement letter",
          amount: "$450.00",
        },
      },
    ];

    <Preview.Content>
      <Preview.Csv columns={columns} rows={rows} />
    </Preview.Content>;
    ```
  </Tab>
</Tabs>

### Email HTML [#email-html]

Use `Preview.Html` for prepared email body HTML. It renders the markup in an
opaque-origin sandbox with scripts, forms, embeds, and remote resources blocked.
Inline email styles remain available, and images resolved by the consumer to
`data:` or `blob:` URLs can render.

The consumer fetches the email and decides whether remote content is trusted.
Resolve approved CID, attachment, or remote image references before passing the
HTML to Cubitt; `Preview.Html` does not fetch or approve them.

<Tabs items="[&#x22;Preview&#x22;, &#x22;Code&#x22;]">
  <Tab value="Preview">
    <Preview name="PreviewHtmlScenario" />
  </Tab>

  <Tab value="Code">
    ```tsx
    import { Preview } from "@tilt-legal/cubitt-components/preview";

    <Preview.Content>
      <Preview.Html html={emailHtml} title="Matter update email body" />
    </Preview.Content>;
    ```
  </Tab>
</Tabs>

### PDF [#pdf]

`Preview.Pdf` receives a ready PDF URL and provides the context shared by its
controls and view. Put `Preview.Pdf.Controls` in the header toolbar so zoom
controls sit alongside consumer-owned actions.

<Tabs items="[&#x22;Preview&#x22;, &#x22;Code&#x22;]">
  <Tab value="Preview">
    <Preview name="PreviewPdfScenario" />
  </Tab>

  <Tab value="Code">
    ```tsx
    import { Preview } from "@tilt-legal/cubitt-components/preview";
    import { Toolbar } from "@tilt-legal/cubitt-components/toolbar";

    <Preview aria-label="PDF preview">
      <Preview.Pdf src={pdfUrl} onError={handleError} onReady={handleReady}>
        <Preview.Header>
          <Toolbar>
            <Toolbar.Heading>
              <Toolbar.Title className="truncate text-base">
                {fileName}
              </Toolbar.Title>
            </Toolbar.Heading>
            <Toolbar.Actions>
              <Preview.Pdf.Controls />
              {actions}
            </Toolbar.Actions>
          </Toolbar>
        </Preview.Header>
        <Preview.Content>
          <Preview.Pdf.View />
        </Preview.Content>
      </Preview.Pdf>
    </Preview>;
    ```
  </Tab>
</Tabs>

### Image [#image]

`Preview.Image` accepts normal image attributes. The consumer supplies the URL,
alternative text, and any load or error handling. The image retains its natural
dimensions and aspect ratio, shrinking only when the available preview area is
smaller.

<Tabs items="[&#x22;Preview&#x22;, &#x22;Code&#x22;]">
  <Tab value="Preview">
    <Preview name="PreviewImageScenario" />
  </Tab>

  <Tab value="Code">
    ```tsx
    import { Preview } from "@tilt-legal/cubitt-components/preview";

    <Preview.Content>
      <Preview.Image alt="Signed agreement on a conference table" src={imageUrl} />
    </Preview.Content>;
    ```
  </Tab>
</Tabs>

### Loading [#loading]

Keep the normal header and actions mounted while the consumer prepares the
content. Disable actions that cannot run until the preview is ready.

<Tabs items="[&#x22;Preview&#x22;, &#x22;Code&#x22;]">
  <Tab value="Preview">
    <Preview name="PreviewLoadingScenario" />
  </Tab>

  <Tab value="Code">
    ```tsx
    import { Button } from "@tilt-legal/cubitt-components/button";
    import { Preview } from "@tilt-legal/cubitt-components/preview";
    import { Toolbar } from "@tilt-legal/cubitt-components/toolbar";
    import { Download } from "@tilt-legal/cubitt-icons/ui/outline";

    <Preview aria-label="Loading attachment preview">
      <Preview.Header>
        <Toolbar>
          <Toolbar.Heading>
            <Toolbar.Title className="truncate text-base">
              {fileName}
            </Toolbar.Title>
          </Toolbar.Heading>
          <Toolbar.Actions>
            <Button
              aria-label="Download preview"
              disabled
              mode="icon"
              variant="secondary"
            >
              <Download />
            </Button>
          </Toolbar.Actions>
        </Toolbar>
      </Preview.Header>
      <Preview.Content>
        <Preview.Loading />
      </Preview.Content>
    </Preview>;
    ```
  </Tab>
</Tabs>

### In a Dialog [#in-a-dialog]

Use `DialogContent` with `fullscreen` when the PDF viewer should temporarily
take over the workspace while preserving its page rail and toolbar controls.

<Tabs items="[&#x22;Preview&#x22;, &#x22;Code&#x22;]">
  <Tab value="Preview">
    <Preview name="PreviewDialogScenario" />
  </Tab>

  <Tab value="Code">
    ```tsx
    import { Button } from "@tilt-legal/cubitt-components/button";
    import { Preview } from "@tilt-legal/cubitt-components/preview";
    import {
      Dialog,
      DialogClose,
      DialogContent,
      DialogTrigger,
    } from "@tilt-legal/cubitt-components/dialog";
    import { Toolbar } from "@tilt-legal/cubitt-components/toolbar";
    import { Xmark } from "@tilt-legal/cubitt-icons/ui/outline";

    <Dialog>
      <DialogTrigger render={<Button variant="secondary" />}>
        Open preview
      </DialogTrigger>
      <DialogContent fullscreen showDismissButton={false}>
        <Preview aria-label="PDF attachment preview dialog">
          <Preview.Pdf src={pdfUrl}>
            <Preview.Header>
              <Toolbar>
                <Toolbar.Heading>
                  <Toolbar.Title className="truncate text-base">
                    engagement-letter.pdf
                  </Toolbar.Title>
                </Toolbar.Heading>
                <Toolbar.Actions>
                  <Preview.Pdf.Controls />
                  <DialogClose
                    aria-label="Close preview"
                    render={<Button mode="icon" variant="secondary" />}
                  >
                    <Xmark />
                  </DialogClose>
                </Toolbar.Actions>
              </Toolbar>
            </Preview.Header>
            <Preview.Content>
              <Preview.Pdf.View />
            </Preview.Content>
          </Preview.Pdf>
        </Preview>
      </DialogContent>
    </Dialog>;
    ```
  </Tab>
</Tabs>

## API Reference [#api-reference]

### Preview [#preview]

Root layout for the preview header and content.

| Prop        | Type        | Default | Description                           |
| ----------- | ----------- | ------- | ------------------------------------- |
| `children`  | `ReactNode` | -       | Header and prepared preview content.  |
| `className` | `string`    | -       | Overrides or extends the root layout. |

Also accepts standard `section` props.

### Preview\.Header [#previewheader]

Fixed translucent header region intended for a consumer-composed `Toolbar`.

| Prop        | Type        | Default | Description                                   |
| ----------- | ----------- | ------- | --------------------------------------------- |
| `children`  | `ReactNode` | -       | Usually a `Toolbar` with a title and actions. |
| `className` | `string`    | -       | Overrides or extends the header layout.       |

Also accepts standard `header` props.

### Preview\.Content [#previewcontent]

Flexible content region containing one preview renderer.

| Prop        | Type        | Default | Description                                 |
| ----------- | ----------- | ------- | ------------------------------------------- |
| `children`  | `ReactNode` | -       | Prepared preview renderer or loading state. |
| `className` | `string`    | -       | Overrides or extends the content layout.    |

Also accepts standard `div` props.

### Preview\.Markdown and Preview\.Text [#previewmarkdown-and-previewtext]

Read-only Cubitt `Editor` renderers using the Markdown content format.

| Prop        | Type     | Default | Description                              |
| ----------- | -------- | ------- | ---------------------------------------- |
| `content`   | `string` | -       | Prepared Markdown or plain text content. |
| `className` | `string` | -       | Overrides or extends the editor root.    |

Also accept standard `div` props except the native `content` attribute.

### Preview\.Csv [#previewcsv]

Standard Cubitt `Table` presentation for consumer-parsed CSV data.

| Prop      | Type                 | Default | Description                                                          |
| --------- | -------------------- | ------- | -------------------------------------------------------------------- |
| `columns` | `PreviewCsvColumn[]` | -       | Ordered column definitions with `id` and `label`.                    |
| `rows`    | `PreviewCsvRow[]`    | -       | Rows with a stable `id` and a string cell record keyed by column id. |
| `caption` | `string`             | -       | Optional accessible table caption.                                   |

Also accepts `ScrollArea` props except `children`.

```ts
type PreviewCsvColumn = {
  id: string;
  label: string;
};

type PreviewCsvRow = {
  id: string;
  cells: Readonly<Record<string, string>>;
};
```

### Preview\.Html [#previewhtml]

Isolated renderer for consumer-prepared email HTML.

| Prop        | Type     | Default | Description                                                                      |
| ----------- | -------- | ------- | -------------------------------------------------------------------------------- |
| `html`      | `string` | -       | Prepared email body HTML. Document-level `meta` and `base` elements are ignored. |
| `title`     | `string` | -       | Required accessible title for the isolated document.                             |
| `className` | `string` | -       | Overrides or extends the iframe layout.                                          |

Also accepts standard `iframe` props except security-sensitive source, sandbox,
permission, referrer, title, child-content, and fullscreen props. The iframe
security policy cannot be weakened through component props.

### Preview\.Pdf [#previewpdf]

Root provider for a prepared PDF URL, zoom controls, and rendered pages.

| Prop       | Type         | Default | Description                                              |
| ---------- | ------------ | ------- | -------------------------------------------------------- |
| `src`      | `string`     | -       | Ready PDF URL or data URL.                               |
| `children` | `ReactNode`  | -       | Header and content containing the PDF controls and view. |
| `onReady`  | `() => void` | -       | Called after the first page renders successfully.        |
| `onError`  | `() => void` | -       | Called once when the PDF source or first page fails.     |

`Preview.Pdf.Controls` renders the built-in zoom controls.
`Preview.Pdf.View` renders the page rail and document pages. Both must be used
inside `Preview.Pdf`.

### Preview\.Image [#previewimage]

| Prop        | Type     | Default | Description                        |
| ----------- | -------- | ------- | ---------------------------------- |
| `src`       | `string` | -       | Ready image URL or data URL.       |
| `alt`       | `string` | -       | Accessible image description.      |
| `className` | `string` | -       | Overrides or extends image styles. |

Also accepts standard `img` props. `alt` is required; `width` and `height` remain
optional when the consumer wants to provide intrinsic metadata.

### Preview\.Loading [#previewloading]

Presentation-only loading state. The consumer decides when loading starts,
finishes, or fails.

| Prop        | Type        | Default             | Description                              |
| ----------- | ----------- | ------------------- | ---------------------------------------- |
| `children`  | `ReactNode` | `"Loading preview"` | Loading message.                         |
| `className` | `string`    | -                   | Overrides or extends the loading layout. |

Also accepts standard `output` props.
