Receipt Card

Pro

The 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.

Show me the receipt for Saturday's groceries
Here is your Whole Foods receipt from Saturday morning. Seven items, paid with your Visa.
WFWhole Foods MarketSat, Oct 31 · 10:42 AMPaid
Total$61.65
2×Oat milk, 64 oz$9.98
1×Sourdough loaf$6.49
1×Hass avocados, bag of 4$5.99
Subtotal
$59.22
Tax
$2.43
Total
$61.65
Visa ending in 4242

Installation#

# One-time setup (tokens + lib helpers)npx koalaui-cli@latest init# Activate your Pro license (once per machine)npx koalaui-cli@latest login <key># Add this component (its dependencies come along)npx koalaui-cli@latest add receipt-card

Usage#

This example is part of Koala UI Pro

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.

FigmaNov 1, 2026Paid
$45.00
Visa ending in 4242
NotionNov 3, 2026Pending
$10.00
Mastercard ending in 8817
UUberOct 12, 2026Refunded
$14.60
Apple Pay
OpenAIOct 28, 2026Failed
$20.00
Visa ending in 0119

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.

WFWhole Foods MarketSat, Oct 31 · 10:42 AMPaid
Total$61.65
2×Oat milk, 64 oz$9.98
1×Sourdough loaf$6.49
1×Hass avocados, bag of 4$5.99
Subtotal
$59.22
Tax
$2.43
Total
$61.65
Visa ending in 4242
WFWhole Foods MarketSat, Oct 31 · 10:42 AMPaid
Total$61.65
2×Oat milk, 64 oz$9.98
1×Sourdough loaf$6.49
1×Hass avocados, bag of 4$5.99
1×Wild sockeye salmon fillet$14.82
3×Greek yogurt, plain$5.97
1×Baby spinach$3.99
2×Sparkling water, 12 pack$11.98
Subtotal
$59.22
Tax
$2.43
Total
$61.65
Visa ending in 4242

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.

Find my Uber receipts from last month
You took four Uber rides in October. Open one to see the fare.
4 rides in October$86.42

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.

PropTypeDefaultDescription
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.
openboolean-Controlled open state of a compact card.
defaultOpenbooleanfalseInitial open state of a compact card.
onOpenChange(open: boolean) => void-Called when a compact card opens or closes.
Data attributeDescription
data-slot"receipt-card".
data-statusThe status.
data-layout"full" or "compact".
data-stateopen 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 attributeDescription
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.

PropTypeDefaultDescription
srcstring-A logo image. The children show until it loads, or if it fails.
altstring""The image's alt text. Empty by default, since the title names the merchant.
Data attributeDescription
data-slot"receipt-card-mark".

ReceiptCardTitle

The merchant, a <span>. Truncates on one line.

Data attributeDescription
data-slot"receipt-card-title".

ReceiptCardDate

When, and optionally what ("Nov 1 · Professional plan"), a muted <span> under the title.

Data attributeDescription
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 attributeDescription
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.

PropTypeDefaultDescription
variantBadgeProps["variant"]-Overrides the tone the status picks.
childrenReact.ReactNode-Overrides the wording (Paid, Pending, Refunded, Failed).
Data attributeDescription
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 attributeDescription
data-slot"receipt-card-content".
data-stateopen or closed, in a compact card.

ReceiptCardTotal

The amount as the hero figure, 30px semibold in tabular-nums. Renders a <div>.

PropTypeDefaultDescription
labelReact.ReactNode-A small caption above the figure.
Data attributeDescription
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.

PropTypeDefaultDescription
maxnumber3How many items show while folded.
openboolean-Controlled: whether every item shows.
defaultOpenbooleanfalseInitial state.
onOpenChange(open: boolean) => void-Called when the toggle is used.
showAllLabel(count: number) => React.ReactNode(count) => Show all ${count} itemsThe folded toggle's wording, given the total count.
showFewerLabelReact.ReactNode"Show fewer"The open toggle's wording.
Data attributeDescription
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>.

PropTypeDefaultDescription
quantityReact.ReactNode-Printed as 2× in the quantity column.
amountReact.ReactNode-The line's amount, right-aligned in tabular-nums.
Data attributeDescription
data-slot"receipt-card-item".

ReceiptCardTotals

Subtotal, tax, tip and total, a <dl> ruled off from the items by a hairline.

Data attributeDescription
data-slot"receipt-card-totals".

ReceiptCardRow

One label and its amount, a <dt> and <dd> in a <div>.

PropTypeDefaultDescription
label*React.ReactNode-What the amount is.
children*React.ReactNode-The amount.
strongbooleanfalseThe row that closes the sum: the label in ink, the amount semibold.
Data attributeDescription
data-slot"receipt-card-row".
data-strongPresent on a strong row.

ReceiptCardFooter

The last line, a <div>: payment on the left, actions on the right, wrapping when narrow.

Data attributeDescription
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.

PropTypeDefaultDescription
brandReact.ReactNode-The card or wallet (Visa, Apple Pay).
last4React.ReactNode-The last four digits. Leave it out for a wallet.
iconReact.ReactNode<CreditCard />The glyph in front.
childrenReact.ReactNode-Replaces the brand and digits with your own wording.
Data attributeDescription
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 attributeDescription
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 attributeDescription
data-slot"receipt-card-group".

ReceiptCardGroupTotal

The sum across the group, a last row under a hairline.

PropTypeDefaultDescription
label*React.ReactNode-What was summed ("4 rides in October").
children*React.ReactNode-The sum.
Data attributeDescription
data-slot"receipt-card-group-total".