# Document Preview

> Shows statements, invoices and contracts inside the product, with a header for pages, zoom, download and print, and a rail of page thumbnails.

Source: https://ritla.app/ui/document-preview

## Installation

Installing from the registry is coming soon. Until then, these are the commands you will run.

```bash
npx ritla add document-preview
```

With the shadcn CLI instead:

```bash
npx shadcn@latest add @ritla/document-preview
```

Dependencies: `@phosphor-icons/react`

## Usage

```tsx
import { DocumentPreview } from "@/components/ui/document-preview";

// Pages come from the app's own renderer: images made on the server, or a library such as
// pdf.js drawing each page to a canvas. The viewer only shows them.
<DocumentPreview
  fileName="Statement_Sep_2026.pdf"
  pages={pageImages.map((src, i) => ({ content: <img src={src} alt={`Page ${i + 1}`} /> }))}
  downloadHref="/statements/2026-09.pdf"
  downloadLabel="Download PDF, 240 KB"
/>
```

## Examples

### The document keeps its direction

An English statement in the viewer, without the rail. In the Arabic preview the header mirrors, and the pages stay English and left to right, because each page carries its own `dir` and `lang`.

Live preview: https://ritla.app/_kanz/preview/ltr/document-preview-own-direction

## API reference

### `DocumentPreview`

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `fileName` | `string` | None | The file name, read left to right. Keep personal data out of it. |
| `pages` | `{ content, dir?, lang?, thumbnail? }[]` | None | The pages as the app renders them, in their own language and direction. The component does not read PDFs: the app renders each page with its own tool, such as server-made images or a library like pdf.js, and passes them here (an `<img>`, a `<canvas>` or content). |
| `pageWidth / pageHeight` | `number` | `560 / 792` | The page size in pixels at 100%. |
| `sidebar` | `boolean` | None | Figma's Sidebar: the thumbnail rail, open by default for three pages or more, hidden on phones. |
| `downloadHref / downloadLabel` | `string` | None | The download link, named with the file's type and size (“Download PDF, 240 KB”). |
| `onPrint` | `() => void` | None | The print button; hidden without it. |
| `menu` | `ReactNode` | None | A More button opening a Menu with the other actions. |

## Accessibility

Keyboard (keys as in left-to-right; arrows swap in right-to-left):

- `Tab`: Through the header buttons, then the thumbnails, then the page area.
- `Enter`: On a thumbnail: goes to that page.
- `ArrowDown` + `ArrowUp`: In the page area: scrolls up and down.

ARIA:

- Every header button has a name: Download, Print, Zoom in, Zoom out, Fit to width, Rotate clockwise.
- The page number follows the scroll and is announced “Page 1 of 3”.
- Thumbnails are buttons in a `nav` named Pages; the current one is `aria-current`.
- The document's text stays selectable when you render it as content, not an image.

## Arabic and RTL notes

Mirrors:

- The menu and file name sit on the right; download and print on the left.
- The thumbnail rail moves to the right.
- The page count reads «1 من 2».

Does not mirror:

- The pages themselves keep their own language and direction.
- The file name stays left to right.
- Rotate turns clockwise, and its icon doesn't mirror.

Numerals: The page number and zoom percentage follow the product's numerals; the document's own figures are as on its pages.

Arabic typography: File name `label-16` Semibold; counters `label-14` and `label-12` Medium, white on the dark bar.

Mixed-direction text: The file name and zoom percentage are isolated LTR.
