- Subtotal
- $59.22
- Tax
- $2.43
- Total
- $61.65
Receipt Card
ProThe receipt an assistant hands back in a chat reply: who charged you, when, how much, what for and on which card. A full card for one receipt, a row that opens in place when there are several.
Installation#
Usage#
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#
A header that names the merchant and the date, and the content under it: the hero total, the line items, the sums and a footer with the card and the actions. Every part under the header is droppable: a subscription charge needs only the total and the card.
import {
ReceiptCardGroup,
ReceiptCardGroupTotal,
ReceiptCard,
ReceiptCardHeader,
ReceiptCardMark,
ReceiptCardTitle,
ReceiptCardDate,
ReceiptCardAmount,
ReceiptCardStatus,
ReceiptCardContent,
ReceiptCardTotal,
ReceiptCardItems,
ReceiptCardItem,
ReceiptCardTotals,
ReceiptCardRow,
ReceiptCardFooter,
ReceiptCardPayment,
ReceiptCardActions,
} from "@/components/ui/receipt-card"
<ReceiptCardGroup>
<ReceiptCard>
<ReceiptCardHeader>
<ReceiptCardMark />
<ReceiptCardTitle />
<ReceiptCardDate />
<ReceiptCardAmount />
<ReceiptCardStatus />
</ReceiptCardHeader>
<ReceiptCardContent>
<ReceiptCardTotal />
<ReceiptCardItems>
<ReceiptCardItem />
</ReceiptCardItems>
<ReceiptCardTotals>
<ReceiptCardRow />
</ReceiptCardTotals>
<ReceiptCardFooter>
<ReceiptCardPayment />
<ReceiptCardActions />
</ReceiptCardFooter>
</ReceiptCardContent>
</ReceiptCard>
<ReceiptCardGroupTotal />
</ReceiptCardGroup>Statuses#
Four, set once on the root with status. The status chip words and tones itself from it, so the label and the state can never drift apart. A refund strikes the total through rather than hiding it: the money moved and came back, and the receipt still says how much. A failed charge mutes the total, since nothing was taken.
Line items#
A chat reply is not the place for a seven-line till roll. ReceiptCardItems shows the first three and folds the rest behind a toggle that counts them; opening it grows the list in place and the toggle's label rolls to “Show fewer”. Set max for a different cut, defaultOpen to start unfolded. The quantity column only appears when an item has a quantity.
- Subtotal
- $59.22
- Tax
- $2.43
- Total
- $61.65
- Subtotal
- $59.22
- Tax
- $2.43
- Total
- $61.65
Compact#
layout="compact" turns the header into one line you can click: the mark, the merchant over the date, the amount over the status. The card itself grows to show the rest, the same object getting taller rather than a panel swapping in. Put the amount in the header with ReceiptCardAmount and leave out the hero total.
Several receipts#
When the assistant finds more than one, stack compact cards in a ReceiptCardGroup. They share one frame and part with hairlines, each opens on its own, and ReceiptCardGroupTotal sums them underneath.
API reference#
ReceiptCard
One receipt, an <article>, and the context every part reads. Every part accepts className, merged last, and forwards its element's props. receiptCardVariants is the recipe.
| Prop | Type | Default | Description |
|---|---|---|---|
| status | "paid" | "pending" | "refunded" | "failed" | "paid" | Where the charge stands. Words and tones ReceiptCardStatus; refunded strikes the hero total through and failed mutes it. |
| layout | "full" | "compact" | "full" | full shows everything at once. compact makes the header a one-line disclosure and folds ReceiptCardContent under it, opening in place. |
| open | boolean | - | Controlled open state of a compact card. |
| defaultOpen | boolean | false | Initial open state of a compact card. |
| onOpenChange | (open: boolean) => void | - | Called when a compact card opens or closes. |
| Data attribute | Description |
|---|---|
| data-slot | "receipt-card". |
| data-status | The status. |
| data-layout | "full" or "compact". |
| data-state | open or closed, on a compact card only. |
ReceiptCardHeader
Who and when, laid out as a two-row grid: the mark, then the title over the date, then the amount over the status. In a compact card it is the Radix Collapsible.Trigger (a <button>) and adds the caret; in a full card it is a <div>.
| Data attribute | Description |
|---|---|
| data-slot | "receipt-card-header". |
ReceiptCardMark
The merchant's mark, an Avatar: 40px in a full card, 32px in a compact one. Children are the fallback, initials or a logo glyph. Forwards Avatar props such as color.
| Prop | Type | Default | Description |
|---|---|---|---|
| src | string | - | A logo image. The children show until it loads, or if it fails. |
| alt | string | "" | The image's alt text. Empty by default, since the title names the merchant. |
| Data attribute | Description |
|---|---|
| data-slot | "receipt-card-mark". |
ReceiptCardTitle
The merchant, a <span>. Truncates on one line.
| Data attribute | Description |
|---|---|
| data-slot | "receipt-card-title". |
ReceiptCardDate
When, and optionally what ("Nov 1 · Professional plan"), a muted <span> under the title.
| Data attribute | Description |
|---|---|
| data-slot | "receipt-card-date". |
ReceiptCardAmount
The total in the header line, a <span> in tabular-nums. Use it in compact rows, where there is no hero total; without it the status centres in its column.
| Data attribute | Description |
|---|---|
| data-slot | "receipt-card-amount". |
ReceiptCardStatus
A dot Badge worded and toned from the root's status, sm in a compact card. Forwards Badge props.
| Prop | Type | Default | Description |
|---|---|---|---|
| variant | BadgeProps["variant"] | - | Overrides the tone the status picks. |
| children | React.ReactNode | - | Overrides the wording (Paid, Pending, Refunded, Failed). |
| Data attribute | Description |
|---|---|
| data-slot | "receipt-card-status". |
ReceiptCardContent
Everything under the header, a <div> stacking its parts 16px apart. In a compact card it is the Radix Collapsible.Content: its height tweens open and shut and the parts fade in with it.
| Data attribute | Description |
|---|---|
| data-slot | "receipt-card-content". |
| data-state | open or closed, in a compact card. |
ReceiptCardTotal
The amount as the hero figure, 30px semibold in tabular-nums. Renders a <div>.
| Prop | Type | Default | Description |
|---|---|---|---|
| label | React.ReactNode | - | A small caption above the figure. |
| Data attribute | Description |
|---|---|
| data-slot | "receipt-card-total"; the figure is "receipt-card-total-value". |
ReceiptCardItems
The line items, a role="list". Shows the first max and folds the rest behind a toggle that reads "Show all 7 items". A quantity column appears only when some item has a quantity. Items must be direct children.
| Prop | Type | Default | Description |
|---|---|---|---|
| max | number | 3 | How many items show while folded. |
| open | boolean | - | Controlled: whether every item shows. |
| defaultOpen | boolean | false | Initial state. |
| onOpenChange | (open: boolean) => void | - | Called when the toggle is used. |
| showAllLabel | (count: number) => React.ReactNode | (count) => Show all ${count} items | The folded toggle's wording, given the total count. |
| showFewerLabel | React.ReactNode | "Show fewer" | The open toggle's wording. |
| Data attribute | Description |
|---|---|
| data-slot | "receipt-card-items"; the fold is "receipt-card-items-more" and the toggle "receipt-card-items-toggle". |
ReceiptCardItem
One line: quantity, name (the children) and amount. Renders a role="listitem" <div>.
| Prop | Type | Default | Description |
|---|---|---|---|
| quantity | React.ReactNode | - | Printed as 2× in the quantity column. |
| amount | React.ReactNode | - | The line's amount, right-aligned in tabular-nums. |
| Data attribute | Description |
|---|---|
| data-slot | "receipt-card-item". |
ReceiptCardTotals
Subtotal, tax, tip and total, a <dl> ruled off from the items by a hairline.
| Data attribute | Description |
|---|---|
| data-slot | "receipt-card-totals". |
ReceiptCardRow
One label and its amount, a <dt> and <dd> in a <div>.
| Prop | Type | Default | Description |
|---|---|---|---|
| label* | React.ReactNode | - | What the amount is. |
| children* | React.ReactNode | - | The amount. |
| strong | boolean | false | The row that closes the sum: the label in ink, the amount semibold. |
| Data attribute | Description |
|---|---|
| data-slot | "receipt-card-row". |
| data-strong | Present on a strong row. |
ReceiptCardFooter
The last line, a <div>: payment on the left, actions on the right, wrapping when narrow.
| Data attribute | Description |
|---|---|
| data-slot | "receipt-card-footer". |
ReceiptCardPayment
How it was paid, a muted <span>. Reads "Visa •••• 4242" to sight and "Visa ending in 4242" to a screen reader.
| Prop | Type | Default | Description |
|---|---|---|---|
| brand | React.ReactNode | - | The card or wallet (Visa, Apple Pay). |
| last4 | React.ReactNode | - | The last four digits. Leave it out for a wallet. |
| icon | React.ReactNode | <CreditCard /> | The glyph in front. |
| children | React.ReactNode | - | Replaces the brand and digits with your own wording. |
| Data attribute | Description |
|---|---|
| data-slot | "receipt-card-payment". |
ReceiptCardActions
The buttons, a <div> pushed to the end of the footer. App UI: size="sm" buttons, text only.
| Data attribute | Description |
|---|---|
| data-slot | "receipt-card-actions". |
ReceiptCardGroup
Several receipts in one frame, a <div>. The cards inside drop their own frame and part with hairlines, so the stack reads as one list. Usually holds compact cards.
| Data attribute | Description |
|---|---|
| data-slot | "receipt-card-group". |
ReceiptCardGroupTotal
The sum across the group, a last row under a hairline.
| Prop | Type | Default | Description |
|---|---|---|---|
| label* | React.ReactNode | - | What was summed ("4 rides in October"). |
| children* | React.ReactNode | - | The sum. |
| Data attribute | Description |
|---|---|
| data-slot | "receipt-card-group-total". |