Doc Upload Match

Checks an uploaded file against the document asked for, so a KYC upload isn't rejected days later for being the wrong side, locked or blurry.

StopsWrong document uploaded for KYC

Installation

pnpm dlx shadcn@latest add https://bollard-ui.vercel.app/r/doc-upload-match.json

The files land in your project. They're yours to edit.

Usage

doc-upload-match-usage.tsx
import { DocUploadMatch, type DocGuess, type DocKind } from "@/components/ui/doc-upload-match"

<DocUploadMatch label="Aadhaar (front)" spec={{ kind: "aadhaar-front" }} value={file} onValueChange={setFile} classify={classify} onAccept={(f) => setAccepted(f.name)} />

What it catches

  • Password-locked PDFs, with how the e-Aadhaar password is formed
  • Multi-page PDFs where one page is expected
  • Images too small, blurry or in HEIC format
  • Screenshots of screenshots
  • The wrong document or side, when you provide a classify function

Props

DocUploadMatch props
PropTypeDefault
label* (required)

Visible label, e.g. "Aadhaar (front)".

string—
spec* (required)

What the slot asks for.

DocSpec—
value

Controlled file.

File | null—
defaultValue

Initial file when uncontrolled.

File | nullnull
onValueChange

Called when a file is chosen or removed.

(file: File | null) => void—
classify

Optional OCR or model check. Gets the file and the cheap signals; return null when unsure. Aborted when the file changes.

(file: File, signals: DocSignals, signal: AbortSignal) => Promise<DocGuess | null>—
blurBelow

Laplacian variance below which a photo counts as blurry.

number—
onAccept

Called with the file and its open issues once the user accepts it (no issues, or "Use anyway").

(file: File, issues: DocIssue[]) => void—
messages

Any visible string.

Partial<Omit<DocUploadMessages, "names" | "needs">> & { names?: Partial<Record<DocKind, string>>; needs?: Partial<Record<DocKind, string>> }—

* required. Also accepts the native props of <div> (className, aria-*, data-*…), passed through to it.

Accessibility

  • Labelled file picker; focus returns to it after a rejection
  • The preview image has empty alt (decorative); status is given in text
  • Checking and result messages use icons plus text

Only what the source does. Test with your own screen reader and content before shipping.

Limitations

This is a UX guard rail. Enforce on the server: Re-validate document type, size and content on the server or with your KYC provider; client checks are hints.

  • Without a classify hook it can't tell which document is in the image
  • Blur and size checks are heuristics and can misjudge some photos
  • Runs in the browser; the file still goes wherever your onAccept sends it

Rules

Rules not yet verified against an official source.

Not verified on 2026-10-17: the UIDAI site did not respond. The e-Aadhaar password rule (first 4 letters of the name in capitals + birth year) is unchecked. Copied components don't update themselves, so re-check after rule changes (see updating a component).

What it stops

Wrong document uploaded for KYC

Also known as

kyc upload · document upload · e-aadhaar pdf · pan upload · file upload · dropzone · id proof · address proof

Field type

Dependencies

Pairs well with