Document Match
ProOrder, receipt and invoice aligned line by line, so you read each line straight across and only the variances are tinted.
| Line | OrderPO-2026-0418 | ReceiptALB-7731 | InvoiceFV-26/1184Suministros Ebro S.L. | Proposed action |
|---|---|---|---|---|
| Nitrile gloves, size M, box of 100GN-100-MMatched | €272.0040 x €6.80 | 40 unitsReceived 14 Oct | €272.0040 x €6.80 | |
| Duct tape, grey, 50 mCA-50Allowed −10% to +2%, this line +1.9%Within tolerance | €99.6024 x €4.15 | 24 unitsReceived 14 Oct | €101.5224 x €4.23+€1.92 | |
| Recycled euro palletPE-1200Allowed ±0%, this line +7.1%Exception | €285.0030 x €9.50 | 28 unitsReceived 14 Oct | €285.0030 x €9.50+2 units | |
| Stretch film, 23 micronFE-23Allowed −10% to +2%, this line +5%Exception | €226.8012 x €18.90 | 12 unitsReceived 14 Oct | €238.2012 x €19.85+€11.40 | |
| Freight and packingNot on the orderMissing | Not on this document | Not received | €35.001 x €35.00 | |
| Thermal labels 100 x 150ET-100150Missing | €120.0010 x €12.00 | 10 unitsReceived 14 Oct | Not invoiced | |
| Net | €1,003.40 | Quantities only | €931.72 | |
| VAT 21% | €210.71 | €195.66 | ||
| Total | €1,214.11 | €1,127.38 |
Installation#
Usage#
The grid matches nothing itself. Run your matching engine, then map each result line to a row: the status of the line, a cell per document, and the cell that disagrees marked with its own status and delta.
The preview is yours to explore. Its code comes with a Pro license, paid once and used in every project.
Have a license? Unlock it here
Anatomy#
import {
DocumentMatch,
DocumentMatchSummary,
DocumentMatchCount,
DocumentMatchNavigator,
DocumentMatchGrid,
DocumentMatchHeader,
DocumentMatchLineHead,
DocumentMatchDocument,
DocumentMatchDocumentTitle,
DocumentMatchDocumentNumber,
DocumentMatchDocumentMeta,
DocumentMatchActionHead,
DocumentMatchBody,
DocumentMatchLine,
DocumentMatchLineHeader,
DocumentMatchLineTitle,
DocumentMatchLineMeta,
DocumentMatchTolerance,
DocumentMatchCell,
DocumentMatchValue,
DocumentMatchValueDetail,
DocumentMatchDelta,
DocumentMatchAction,
DocumentMatchTotals,
DocumentMatchTotal,
DocumentMatchTotalLabel,
} from "@/components/ui/document-match"Two-way match#
The grid takes any number of documents. A service has nothing to receive, so it matches the order against the invoice. Here navigate is set to exceptions, so the lines within tolerance are skipped.
| Line | OrderPO-2026-0392 | InvoiceCT-2026-311Climatización Turia S.L. |
|---|---|---|
| Quarterly HVAC serviceFixed feeMatched | €480.00 | €480.00 |
| Call-out labour, 6 hPer hourAllowed ±2%, this line +1.8%Within tolerance | €342.00 | €348.00+€6.00 |
| G4 filter setPartsAllowed ±2%, this line +21.4%Exception | €126.00 | €153.00+€27.00 |
| ParkingNot on the orderMissing | Not ordered | €18.00 |
Tolerance#
The track is the allowed band around the reference, and the dot is where the line landed: grey when exact, amber inside the band, red outside it. Hover it for the numbers.
Card and density#
On its own page the grid needs no frame. Set variant="card" when it sits beside other panels, and density="compact" for a tighter workspace.
| Line | OrderPO-2026-0418 | ReceiptALB-7731 | InvoiceFV-26/1184Suministros Ebro S.L. | Proposed action |
|---|---|---|---|---|
| Nitrile gloves, size M, box of 100GN-100-MMatched | €272.0040 x €6.80 | 40 unitsReceived 14 Oct | €272.0040 x €6.80 | |
| Duct tape, grey, 50 mCA-50Allowed −10% to +2%, this line +1.9%Within tolerance | €99.6024 x €4.15 | 24 unitsReceived 14 Oct | €101.5224 x €4.23+€1.92 | |
| Recycled euro palletPE-1200Allowed ±0%, this line +7.1%Exception | €285.0030 x €9.50 | 28 unitsReceived 14 Oct | €285.0030 x €9.50+2 units | |
| Stretch film, 23 micronFE-23Allowed −10% to +2%, this line +5%Exception | €226.8012 x €18.90 | 12 unitsReceived 14 Oct | €238.2012 x €19.85+€11.40 | |
| Freight and packingNot on the orderMissing | Not on this document | Not received | €35.001 x €35.00 | |
| Thermal labels 100 x 150ET-100150Missing | €120.0010 x €12.00 | 10 unitsReceived 14 Oct | Not invoiced | |
| Net | €1,003.40 | Quantities only | €931.72 | |
| VAT 21% | €210.71 | €195.66 | ||
| Total | €1,214.11 | €1,127.38 |
Keyboard#
The grid is one tab stop. From a line:
- ↓ ↑ move to the next or previous line.
- N P jump to the next or previous variance.
- Home End go to the first or last line.
- Tab moves into the line's proposed action.
API reference#
DocumentMatch
The frame and the context every part reads. It tracks the active line and walks the variances. Every part accepts className, merged last.
| Prop | Type | Default | Description |
|---|---|---|---|
| value | string | null | - | The active line, when you control it. |
| defaultValue | string | null | null | The line active on the first render. |
| onValueChange | (value: string) => void | - | A line was focused or picked with the keyboard. |
| navigate | "variances" | "exceptions" | "variances" | What n and p jump between: every line that is not a match, or only exceptions and missing lines. |
| variant | "plain" | "card" | "plain" | No chrome for a page, or a framed surface. |
| density | "comfortable" | "compact" | - | Cell padding. Reads DensityProvider when unset. |
DocumentMatchCount
One figure in DocumentMatchSummary. Children replace the noun.
| Prop | Type | Default | Description |
|---|---|---|---|
| status* | "match" | "within" | "exception" | "missing" | - | Sets the dot and counts the lines in that state. |
| count | number | - | Overrides the count, for a figure that has to be right on the server render. |
DocumentMatchNavigator
Previous and next buttons for the variances, with the position between them. They move focus to the line.
| Prop | Type | Default | Description |
|---|---|---|---|
| previousLabel | string | "Previous variance" | Accessible name of the previous button. |
| nextLabel | string | "Next variance" | Accessible name of the next button. |
| position | (index: number, total: number) => ReactNode | - | Draws the position. index is -1 when the active line is not a variance. |
DocumentMatchGrid
The scrolling table. On a narrow screen it scrolls sideways and the line column stays pinned. Forwards <table> props; give it an aria-label.
DocumentMatchDocument
A column head for one document. Compose DocumentMatchDocumentTitle, DocumentMatchDocumentNumber and DocumentMatchDocumentMeta inside it.
DocumentMatchLine
One line, read across every document. It is a stop for the keyboard: arrow keys walk the lines, n and p jump between variances.
| Prop | Type | Default | Description |
|---|---|---|---|
| value* | string | - | Identifies the line for value and onValueChange. |
| status | "match" | "within" | "exception" | "missing" | "match" | Drives the mark in the line header and whether n and p stop on it. |
| statusLabel | string | - | The status as read by a screen reader. Use it to translate. |
DocumentMatchLineHeader
The first cell of a line, pinned on scroll. Draws the status mark; compose DocumentMatchLineTitle and DocumentMatchLineMeta inside it.
DocumentMatchCell
One document's value for the line. Only a variance is tinted; a missing cell is hatched.
| Prop | Type | Default | Description |
|---|---|---|---|
| status | "match" | "within" | "exception" | "missing" | - | Tints the cell and colours its delta. Leave it unset on the reference document. |
| missingLabel | ReactNode | "Missing" | Shown in an empty cell with status="missing". |
DocumentMatchDelta
The signed difference against the reference, in tabular numerals.
| Prop | Type | Default | Description |
|---|---|---|---|
| value* | number | - | Positive for over, negative for under. |
| format | (magnitude: number) => string | String | Formats the magnitude; the sign is added for you. |
DocumentMatchTolerance
The allowed band as a small track, with the line's deviation marked on it and a tooltip that spells it out. Ratios, so 0.02 is 2%.
| Prop | Type | Default | Description |
|---|---|---|---|
| over* | number | - | How far over the reference is allowed. |
| under | number | over | How far under is allowed. |
| value | number | - | The line's deviation. Leave it out to show only the band. |
| description | string | - | Replaces the tooltip and screen reader text. Use it to translate. |
DocumentMatchAction
The proposed action for the line, at the end of the row. Buttons inside take the small size. Render it empty to keep the column.
DocumentMatchTotals
The footer. Each DocumentMatchTotal row holds a DocumentMatchTotalLabel and one DocumentMatchCell per document; the last row reads as the total.