# OCR Upload (/docs/components/ocr-upload)



<ComponentPreview name="ocr-upload" />

## Installation [#installation]

<Tabs items="[&#x22;Command&#x22;, &#x22;Manual&#x22;]">
  <Tab value="Command">
    <CodeBlockTabs defaultValue="npm">
      <CodeBlockTabsList>
        <CodeBlockTabsTrigger value="npm">
          npm
        </CodeBlockTabsTrigger>

        <CodeBlockTabsTrigger value="pnpm">
          pnpm
        </CodeBlockTabsTrigger>

        <CodeBlockTabsTrigger value="yarn">
          yarn
        </CodeBlockTabsTrigger>

        <CodeBlockTabsTrigger value="bun">
          bun
        </CodeBlockTabsTrigger>
      </CodeBlockTabsList>

      <CodeBlockTab value="npm">
        ```bash
        npx shadcn@latest add @uploadcn/ocr-upload
        ```
      </CodeBlockTab>

      <CodeBlockTab value="pnpm">
        ```bash
        pnpm dlx shadcn@latest add @uploadcn/ocr-upload
        ```
      </CodeBlockTab>

      <CodeBlockTab value="yarn">
        ```bash
        yarn dlx shadcn@latest add @uploadcn/ocr-upload
        ```
      </CodeBlockTab>

      <CodeBlockTab value="bun">
        ```bash
        bun x shadcn@latest add @uploadcn/ocr-upload
        ```
      </CodeBlockTab>
    </CodeBlockTabs>

    For a server engine, add the route too:

    <CodeBlockTabs defaultValue="npm">
      <CodeBlockTabsList>
        <CodeBlockTabsTrigger value="npm">
          npm
        </CodeBlockTabsTrigger>

        <CodeBlockTabsTrigger value="pnpm">
          pnpm
        </CodeBlockTabsTrigger>

        <CodeBlockTabsTrigger value="yarn">
          yarn
        </CodeBlockTabsTrigger>

        <CodeBlockTabsTrigger value="bun">
          bun
        </CodeBlockTabsTrigger>
      </CodeBlockTabsList>

      <CodeBlockTab value="npm">
        ```bash
        npx shadcn@latest add @uploadcn/ocr-route
        ```
      </CodeBlockTab>

      <CodeBlockTab value="pnpm">
        ```bash
        pnpm dlx shadcn@latest add @uploadcn/ocr-route
        ```
      </CodeBlockTab>

      <CodeBlockTab value="yarn">
        ```bash
        yarn dlx shadcn@latest add @uploadcn/ocr-route
        ```
      </CodeBlockTab>

      <CodeBlockTab value="bun">
        ```bash
        bun x shadcn@latest add @uploadcn/ocr-route
        ```
      </CodeBlockTab>
    </CodeBlockTabs>
  </Tab>

  <Tab value="Manual">
    Install [Upload](/docs/components/upload) and the shadcn `button` component, then copy:

    <ComponentSource name="ocr-upload" />
  </Tab>
</Tabs>

## Usage [#usage]

```tsx
import { ocrEndpoint } from "@uploadcn/core"

import { OcrUpload } from "@/components/ocr-upload"
```

```tsx
<OcrUpload
  recognize={ocrEndpoint("/api/ocr")}
  onResult={(item, result) => saveText(item.result.key, result.text)}
/>
```

Files upload through your [adapter](/docs/storage) as usual; after each one is stored, its
text is read and shown. The engine is up to you:

* `ocrEndpoint("/api/ocr")`: your route, with Google Vision, AWS Textract, Azure Document
  Intelligence, Mistral or your own service. Keys stay on the server.
* `tesseractOcr({ load: () => import("tesseract.js") })`: in the browser, with nothing
  uploaded for OCR. The preview above uses it.

See the [OCR guide](/docs/guides/ocr) for every provider.

## Fields [#fields]

Engines with document models return structured fields: Textract's `expense` model and
Azure's `prebuilt-receipt` and `prebuilt-invoice` give `merchant`, `date`, `total`,
`subtotal`, `tax` and more. The block lists them above the text.

## Accessibility [#accessibility]

Documents are a listbox; the text is a focusable, labelled region you can scroll with the
keyboard. Progress and "Reading text…" are announced politely.

## Props [#props]

<TypeTable
  type="{
  recognize: {
    type: &#x22;OcrRecognizer&#x22;,
    description:
      &#x22;Reads the text: `ocrEndpoint(url)`, `tesseractOcr(...)` or your own function.&#x22;,
    required: true,
  },
  adapter: {
    type: &#x22;UploadAdapter&#x22;,
    description:
      &#x22;Where files go. Defaults to the UploadConfigProvider adapter.&#x22;,
  },
  required: {
    type: &#x22;boolean&#x22;,
    default: &#x22;false&#x22;,
    description: &#x22;Reject the upload when text can't be read.&#x22;,
  },
  accept: {
    type: &#x22;string&#x22;,
    default: '&#x22;image/png,image/jpeg,image/webp,image/tiff,application/pdf&#x22;',
  },
  maxSize: { type: &#x22;number&#x22;, default: &#x22;20 MB&#x22; },
  maxFiles: { type: &#x22;number&#x22;, default: &#x22;20&#x22; },
  onResult: {
    type: &#x22;(item, result: OcrResult) => void&#x22;,
    description: &#x22;Each file's text, once read.&#x22;,
  },
  className: { type: &#x22;string&#x22; },
}"
/>
