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.
Expense claim
Claim 0142 · Gaugeworks travel
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.
| Prop | Type | Default | Description |
|---|---|---|---|
| receipt / defaultReceipt | ReceiptDoc | null | — / 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 | — | Fires when a receipt is dropped, read or cleared. |
| sample | ReceiptDoc | null | defaultReceiptSample | Offered as Use sample and read through the same path as a dropped file; null hides the button. |
| parse | (file: File) => Promise<ReceiptDoc> | — | Your reader. Without one, a dropped file is shown and falls back to a blank claim. |
| onParse | (receipt) => void | — | A receipt was read, before its values travel into the claim. |
| values / defaultValues | ReceiptClaim | — / blank | The claim { merchant, date, amount, category, note }, controlled or initial. |
| onValuesChange | (values) => void | — | Fires from every change to the claim, typed or read. |
| onChange | (field, value, values) => void | — | Fires when you edit a field. |
| onSubmit | (claim) => void | Promise<void> | — | 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" | "box" | How read regions are marked: rounded boxes, corner brackets, or a highlighter band. |
| layout | "side" | "stack" | "flip" | "side" | Receipt beside the claim, above it as a short scrolling strip, or on its right. Below 30rem it always sits above. |
| accent | string | "var(--accent-bright)" | Outlines, the scan line, the travelling values and the field wash, any CSS colour. |
| confidenceThreshold | number | 0.8 | Readings below this confidence land flagged for a check until you edit them. |
| categories | string[] | ["Meals", "Travel", "Lodging", "Supplies", "Other"] | Category choices. |
| currency | string | "EUR" | ISO 4217 code for the amount's symbol and the total in the footer. |
| scanMs | number | 1400 | How long the sample takes to read, in ms. |
| title | string | "Expense claim" | The form's heading and accessible name. |
| subtitle | string | "Claim 0142 · Gaugeworks travel" | A quiet line under the heading. |
| height | number | 520 | Panel height in px; the claim and the receipt scroll inside it. |
| disabled | boolean | false | Nothing can be dropped, edited or sent. |
| className | string | — | Classes for the outer container. |