Receipt
betaWhat was paid, by whom, when, and how, with the status after the title. A declined payment puts its fixes where it is said.
Preview
paid, by, when, method, reference
October subscriptionPaid
- Team plan£15
Total£15
- Paid by
- When
- Tue 29 Sep, 18:04
- Method
- Visa ending 4242
- Reference
- INV-0042
declined, note, onRetry, onChangeCard
October subscriptionDeclined
Your bank turned it down. No money was taken.
- Team plan£15
Total£15
- When
- Tue 29 Sep, 18:04
- Method
- Visa ending 4242
Nothing pressed yet
refunded, a discount with pence, in a Sheet
Install
1. Add the registry to
components.json, once per app. Without it, the shadcn CLI looks up@txbrendanin a public list that txbrendan/ui does not control.npx shadcn@latest registry add "@txbrendan=https://txbrendan.dev/r/{name}.json"2. Add the theme, once per app. It replaces your color tokens with ones checked for contrast.
npx shadcn@latest add @txbrendan/theme3. Add the component.
npx shadcn@latest add @txbrendan/receipt
Use it for
- A payment's record, inside a Card or a Sheet. It draws no box of its own.
- status follows the title as colored text: Paid in success, Processing in brand, Refunded in neutral, Declined in danger.
- A declined payment: onRetry puts a retry icon right beside Declined, note says why in plain words, and onChangeCard adds Try another card under it.
- A refund's note can say where the money went, like "£15 back to Visa ending 4242 on Wed 30 Sep".
- A discount is a negative amount. It shows a true minus, like −£20, and screen readers hear "minus £20".
- Amounts show pence only when some amount has them, so the column lines up.
Avoid it for
- A badge or a box for the status. The status is colored words after the title.
- A list of payments. Use DataTable or ListRow, and open a Receipt from a row.
Props
- title
Required. What was paid for, like "October subscription".
string
- status
Shown as Paid, Processing, Refunded, or Declined.
"paid" | "pending" | "refunded" | "declined"
- note
One line under the title, in ink.
string
- lines
What the total is made of. A negative amount is a discount.
{ label: string; amount: number; meta?: string }[]
- total
Default the sum of the lines.
number
- currency
The money sign.
string · default "£"
- by
Who paid, drawn by Person with their photo.
{ person: string; photo?: string }
- when
Like "Tue 29 Sep, 18:04".
string
- method
Like "Visa ending 4242".
string
- reference
The payment's reference.
string
- onRetry
Declined: a retry icon beside Declined. Return a promise and it waits, and a failure turns it into Retry.
() => void | Promise<unknown>
- retryLabel
Names the retry icon, in its tooltip.
string · default "Try again"
- onChangeCard
Declined: a quiet text button with a card icon, under the note.
() => void
- changeCardLabel
Its words.
string · default "Try another card"
- className
Extra classes on the root. Later classes win.
string
| Prop | Type | Default | What it does |
|---|---|---|---|
| title | string | - | Required. What was paid for, like "October subscription". |
| status | "paid" | "pending" | "refunded" | "declined" | - | Shown as Paid, Processing, Refunded, or Declined. |
| note | string | - | One line under the title, in ink. |
| lines | { label: string; amount: number; meta?: string }[] | - | What the total is made of. A negative amount is a discount. |
| total | number | - | Default the sum of the lines. |
| currency | string | "£" | The money sign. |
| by | { person: string; photo?: string } | - | Who paid, drawn by Person with their photo. |
| when | string | - | Like "Tue 29 Sep, 18:04". |
| method | string | - | Like "Visa ending 4242". |
| reference | string | - | The payment's reference. |
| onRetry | () => void | Promise<unknown> | - | Declined: a retry icon beside Declined. Return a promise and it waits, and a failure turns it into Retry. |
| retryLabel | string | "Try again" | Names the retry icon, in its tooltip. |
| onChangeCard | () => void | - | Declined: a quiet text button with a card icon, under the note. |
| changeCardLabel | string | "Try another card" | Its words. |
| className | string | - | Extra classes on the root. Later classes win. |
Accessibility
- The status is words, so it never leans on color alone.
- The retry icon is a real button named by retryLabel, in its tooltip too. Try another card is a real button with words.
- A discount is read as "minus £20", and the true minus sign shows.
- The payer, the time, the method, and the reference are a description list, so each is read with its label.
Examples
Paid
<Receipt
title="October subscription"
status="paid"
lines={[{ label: "Team plan", meta: "1 to 31 Oct", amount: 15 }]}
by={{ person: "Kate Clarke" }}
when="Tue 29 Sep, 18:04"
method="Visa ending 4242"
reference="INV-0042"
/>Declined
<Receipt
title="October subscription"
status="declined"
note="Your bank turned it down. No money was taken."
onRetry={() => retry()}
onChangeCard={() => openCards()}
lines={[{ label: "Team plan", amount: 15 }]}
/>