KQ-1671 · RECEIPT/READER

Receipt Reader

An expense claim that fills itself from a receipt: while your reader works a scanning line sweeps the image, and when it answers each place it read is outlined on the receipt in a cascade, then its value lifts out as a small chip that travels into its field — x on springs.glide, y on springs.snap, so the path bows — landing with an accent wash, and readings the reader was unsure of land flagged for a check. Focusing or hovering a field later lights its region again while the others dim, panning the receipt to it when it is out of view. Every value stays editable, Tab moves field to field, Choose file is a real file input, and a failed read keeps the image and falls back to a blank claim.

KQ-1671 · RECEIPT/READER

Expense claim

Claim 0142 · Gaugeworks travel

4 read · 1 to check

Read from the header · 97%

Read from the date line · 93%

Read from the total line · 99%

Check

Read at 62% confidence from the item lines; check it

€18.40

4 fields read · 1 to check · gaugeworks travel

Install

One command — the source lands in your repo. Or copy it from the Code tab.

$ pnpm dlx shadcn@latest add @kinetiq/receipt-reader

Props

receipt / defaultReceipt
ReceiptDoc | null
default — / null
The receipt on show, already read: { src?, alt, aspect, fields }, each reading { value, region: { x, y, w, h } as 0–1 fractions, confidence, source? }. Null shows the drop zone; no src draws the sample in code.
onReceiptChange
(receipt | null) => void
default —
Fires when a receipt is dropped, read or cleared.
sample
ReceiptDoc | null
default defaultReceiptSample
Offered as Use sample and read through the same path as a dropped file; null hides the button.
parse
(file: File) => Promise<ReceiptDoc>
default —
Your reader. Without one, a dropped file is shown and falls back to a blank claim.
onParse
(receipt) => void
default —
A receipt was read, before its values travel into the claim.
values / defaultValues
ReceiptClaim
default — / blank
The claim { merchant, date, amount, category, note }, controlled or initial.
onValuesChange
(values) => void
default —
Fires from every change to the claim, typed or read.
onChange
(field, value, values) => void
default —
Fires when you edit a field.
onSubmit
(claim) => void | Promise<void>
default —
Submit with every required field valid. A promise shows progress on the button; a rejection keeps the claim and offers Try again.
outlineStyle
"box" | "corners" | "marker"
default "box"
How read regions are marked: rounded boxes, corner brackets, or a highlighter band.
layout
"side" | "stack" | "flip"
default "side"
Receipt beside the claim, above it as a short scrolling strip, or on its right. Below 30rem it always sits above.
accent
string
default "var(--accent-bright)"
Outlines, the scan line, the travelling values and the field wash, any CSS colour.
confidenceThreshold
number
default 0.8
Readings below this confidence land flagged for a check until you edit them.
categories
string[]
default ["Meals", "Travel", "Lodging", "Supplies", "Other"]
Category choices.
currency
string
default "EUR"
ISO 4217 code for the amount's symbol and the total in the footer.
scanMs
number
default 1400
How long the sample takes to read, in ms.
title
string
default "Expense claim"
The form's heading and accessible name.
subtitle
string
default "Claim 0142 · Gaugeworks travel"
A quiet line under the heading.
height
number
default 520
Panel height in px; the claim and the receipt scroll inside it.
disabled
boolean
default false
Nothing can be dropped, edited or sent.
className
string
default —
Classes for the outer container.