# Receipt Upload (/docs/components/receipt-upload)



<ComponentPreview name="receipt-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/receipt-upload
        ```
      </CodeBlockTab>

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

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

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

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

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

## Usage [#usage]

```tsx
import { ReceiptUpload } from "@/components/receipt-upload"
```

With OCR, the form fills itself. Textract's `expense` model and Azure's
`prebuilt-receipt` return the fields directly; other engines are read from the text:

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

;<ReceiptUpload
  recognize={ocrEndpoint("/api/ocr")} // npx shadcn@latest add @uploadcn/ocr-route
  onSubmit={(expense) => createExpense(expense)}
/>
```

Or extract the fields yourself, with any API or model:

```tsx
<ReceiptUpload
  extract={async (item) => {
    const response = await fetch(`/api/receipts/${item.result.key}/ocr`)
    return response.json() // { merchant, date, amount, category }
  }}
  onSubmit={(expense) => createExpense(expense)}
/>
```

On phones the picker opens the rear camera (`capture="environment"`). Fields the user already typed are never overwritten. `receiptFromOcr(result)` is exported if you want the same mapping elsewhere. See the [OCR guide](/docs/guides/ocr) for providers.

## Props [#props]

<TypeTable
  type="{
  adapter: {
    type: &#x22;UploadAdapter&#x22;,
    default: 's3Adapter({ endpoint: &#x22;/api/upload&#x22; })',
    description: &#x22;Where files go.&#x22;,
  },
  uploader: {
    type: &#x22;Uploader&#x22;,
    description: &#x22;An uploader from `useUploader`, instead of options.&#x22;,
  },
  categories: { type: &#x22;string[]&#x22; },
  recognize: {
    type: &#x22;OcrRecognizer&#x22;,
    description:
      &#x22;Read the receipt with OCR and prefill merchant, date and amount.&#x22;,
  },
  extract: {
    type: &#x22;(item) => Promise<Partial<ReceiptFields>>&#x22;,
    description:
      &#x22;Prefill from your own OCR or AI after upload. Wins over `recognize`.&#x22;,
  },
  onSubmit: { type: &#x22;(expense) => void&#x22; },
  className: { type: &#x22;string&#x22; },
}"
/>
