KQ-680 · INVOICE/BUILD
Invoice Build
An invoice that does its own arithmetic in front of you: a new line opens from zero to a ResizeObserver-measured height on glide while its content slides in from 16px, and the subtotal, tax and total roll their digit columns to the new figures on snap. Removing a line closes the same measured height on the exit ease, which accelerates away rather than springing back, and the figures roll down as it goes. Every remove is a real button carrying its line's description, and removing the row you are standing on hands focus to the next one, so a keyboard run of deletions never dumps focus on the body.
- Rig hire, 3 at $120.00, $360.00
- Site survey, 1 at $480.00, $480.00
- Cable spool, 12 at $18.50, $222.00
- Subtotal
- Subtotal $1,062.00
- Tax 8%
- Tax 8 percent, $84.96
- Total
- Total $1,146.96
Fernworks Fabrication · net 14 days
Total $1,146.96 across 3 linesLines 3 · total $0.00
Install
One command — the source lands in your repo. Or copy it from the Code tab.
$ pnpm dlx shadcn@latest add @kinetiq/invoice-build
Props
- lines
- InvoiceLine[]
- default —
- The lines: id, description, qty and unitPrice. Adding one slides it in; removing one collapses it.
- onRemove
- (id: string) => void
- default —
- Fires from the press on a line's remove button; drop the line to play the collapse.
- taxRate
- number
- default 0.08
- Fraction of the subtotal charged as tax; the rate is printed as a percentage in the tax label.
- format
- (value: number) => string
- default Intl.NumberFormat("en-US", { style: "currency", currency: "USD" })
- Turns an amount into its printed string. The default pins an explicit locale so server and client agree.
- onTotalChange
- (total: number, subtotal: number, tax: number) => void
- default —
- Fires from the effect that observes a settled change of the three figures.
- label
- string
- default "Invoice"
- Names the line list and the totals for assistive technology.
- note
- React.ReactNode
- default —
- A quiet caption under the totals — the account or the terms.
- emptyLabel
- string
- default "No lines yet."
- The designed empty state; no height is reserved for it.
| Prop | Type | Default | Description |
|---|---|---|---|
| lines | InvoiceLine[] | — | The lines: id, description, qty and unitPrice. Adding one slides it in; removing one collapses it. |
| onRemove | (id: string) => void | — | Fires from the press on a line's remove button; drop the line to play the collapse. |
| taxRate | number | 0.08 | Fraction of the subtotal charged as tax; the rate is printed as a percentage in the tax label. |
| format | (value: number) => string | Intl.NumberFormat("en-US", { style: "currency", currency: "USD" }) | Turns an amount into its printed string. The default pins an explicit locale so server and client agree. |
| onTotalChange | (total: number, subtotal: number, tax: number) => void | — | Fires from the effect that observes a settled change of the three figures. |
| label | string | "Invoice" | Names the line list and the totals for assistive technology. |
| note | React.ReactNode | — | A quiet caption under the totals — the account or the terms. |
| emptyLabel | string | "No lines yet." | The designed empty state; no height is reserved for it. |