Receipt

A slip of thermal paper: a till receipt, a parking ticket, the printout of a breathalyzer. Cream paper in every theme with a torn edge, a monospace print face, dashed rules, label and value rows, a headline figure, a verdict stamp and the small print, each part optional.

Police Report

Breath alcohol test

Subject: Daniel Ortega
Date: 10/10/2026 14:52
Officer: Sgt. R. Okafor

Result

0.32

mg/L of breath

Positive · Over limit

Legal limit: 0.25 mg/L

Approved ALCO-TEST device

The driver is over the legal alcohol limit.

Bayview PD

Installation#

# One-time setup (tokens + lib helpers)npx koalaui-cli@latest init# Add this component (its dependencies come along)npx koalaui-cli@latest add receipt

Usage#

usage.tsxTSX
import {  Receipt,  ReceiptFooter,  ReceiptHeader,  ReceiptRow,  ReceiptTitle,} from "@/components/ui/receipt"export function Example() {  return (    <Receipt>      <ReceiptHeader>        <ReceiptTitle>Parking Ticket</ReceiptTitle>      </ReceiptHeader>      <ReceiptRow label="Plate:">8KTR204</ReceiptRow>      <ReceiptRow label="Paid until:">16:30</ReceiptRow>      <ReceiptFooter>City of Bayview</ReceiptFooter>    </Receipt>  )}

Anatomy#

Every part is optional but the paper, and they print in the order you write them. The header and the footer bring their own strong rule; a ReceiptRule that would double one of them, or lands at either end of the slip, folds away.

import {  Receipt,  ReceiptFigure,  ReceiptFooter,  ReceiptHeader,  ReceiptNote,  ReceiptRow,  ReceiptRule,  ReceiptStamp,  ReceiptSubtitle,  ReceiptTitle,} from "@/components/ui/receipt"<Receipt size="md" edge="bottom">  {/* The heading, ruled off underneath */}  <ReceiptHeader>    <ReceiptTitle />    <ReceiptSubtitle />  </ReceiptHeader>  {/* The body: rows, rules, a figure, a verdict */}  <ReceiptRow label="Label:">Value</ReceiptRow>  <ReceiptRule />  <ReceiptFigure caption="Result" unit="Unit">0.00</ReceiptFigure>  <ReceiptStamp tone="success" />  <ReceiptNote />  {/* The brand line, ruled off above */}  <ReceiptFooter /></Receipt>

Fingerprint record#

A code reads better a step smaller than a reading: size="md" on the figure. A long value, like this one, breaks anywhere rather than running off the paper.

Fingerprint Record

AFIS · Automated fingerprint system

Subject: Maya Chen
CID: KQX48213
Date: 10/10/2026 15:07
Officer: Dep. A. Moreno

Fingerprint

Lx482B19Ajk7730

Match · On record
Registered: 03/14/2024

Approved AFIS SCANNER device

The subject is on record in the fingerprint database.

Bayview PD

Shop receipt#

Line items are rows too: a long item name wraps inside its own share of the line and the price keeps the right edge. A total is a row set larger, with a class. Torn at both ends, the slip reads as cut from the roll.

Harbor Coffee

1200 Harbor Way · Bayview

Order: #0417
Cashier: Priya
2 × Flat white $9.00
1 × Almond croissant $4.25
1 × Cold brew, large, oat milk $5.75
Subtotal $19.00
Tax 8.5% $1.62
Total $20.62
Visa •••• 4242 $20.62
Paid
Thank you! Returns within 14 days with this receipt.
10/10/202614:52

Sizes#

md (the default, 20rem) is the ticket a dialog shows. sm (14rem) is the stub a handheld device feeds out, printed a step smaller. Its rows can run inline, the value straight after the label, with layout="inline"; a tone on a row prints its value bold in that ink.

Police Report

Subject: Daniel Ortega
Result: 0.32 mg/L
Status: Positive · Over the limit

Test taken with an approved ALCO-TEST device.

Legal limit: exceeded

Police Report

Breath alcohol test

Subject: Daniel Ortega
Date: 10/10/2026 14:52
Officer: Sgt. R. Okafor

Result

0.32

mg/L of breath

Positive · Over limit

Legal limit: 0.25 mg/L

Approved ALCO-TEST device

The driver is over the legal alcohol limit.

Bayview PD

Edges#

edge picks the torn ends: bottom (the default, the slip as it leaves the printer), top, both (cut from the roll) or none. The teeth have a fixed size, --receipt-tooth (2em), and a whole number of them fits any width. The torn side keeps its copy clear of them.

bottom

Edge: bottom
Size: sm

top

Edge: top
Size: sm

both

Edge: both
Size: sm

none

Edge: none
Size: sm

Tones#

ReceiptStamp, ReceiptFigure and ReceiptRow take a tone: default (the ink), success, warning, destructive and info. On the paper they are the light theme's -strong inks, legible on cream in any theme; the stamp adds the soft tint and edge of a Badge. Pick the tone by what the verdict means, not by its word: a positive breath test is destructive.

Copy
Negative · Under limit
New record
Positive · Over limit
Copy for the driver

Reading

0.08

mg/L of breath

Status: Negative
Record: New
Fine: $500.00
Copy: Driver

In a dialog#

To show a printed ticket on its own, strip the dialog to nothing and let the slip float on the scrim: the content goes transparent, unpadded and as wide as the receipt. The title stays for screen readers, and a white button under the slip closes it.

Koala has no dot-matrix face, so the receipt prints in the mono token, font-mono. Every size inside it is in em of the receipt's own font size, so a face is swapped, and resized, on the root alone. A pixel face such as VT323 has small glyphs for its size: set it one step up, text-base on md and text-sm on sm. Name the family with font-[family-name:…] so it replaces font-mono instead of sitting beside it. The width stays in rem.

Police Report

Breath alcohol test

Subject: Daniel Ortega
Date: 10/10/2026 14:52
Officer: Sgt. R. Okafor

Result

0.32

mg/L of breath

Positive · Over limit

Legal limit: 0.25 mg/L

Approved ALCO-TEST device

Bayview PD

Police Report

Breath alcohol test

Subject: Daniel Ortega
Date: 10/10/2026 14:52
Officer: Sgt. R. Okafor

Result

0.32

mg/L of breath

Positive · Over limit

Legal limit: 0.25 mg/L

Approved ALCO-TEST device

Bayview PD

Re-tinting#

The receipt scopes itself .light.cream, so its ground and inks are the cream theme's on any page, and keeps its own roles on top of them. Set one on the root to re-tint a slip: --receipt-paper, --receipt-ink, --receipt-muted, --receipt-faint, --receipt-rule, --receipt-rule-strong, and --receipt-tooth for the size of the teeth.

Valet Ticket

The Grand · Bayview

Ticket no.

A-0291

Plate: 8KTR204
In: 19:40
Keep this ticket

Old engines#

Receipt holds in old embedded Chromium too, the kind a desktop or game shell ships (Chromium 10x): no container queries, no :has() and no standalone translate or scale. The torn edge is a mask written both prefixed and unprefixed (the unprefixed mask only arrived in Chromium 120), made of conic gradients, which Chromium has drawn since 69. To slide a ticket out of a device, move the root with [transform:translateY(…)] rather than translate-y-*, which compiles to the standalone translate property.

API reference#

Receipt

The slip, an <article> scoped .light.cream, with the paper inside it (a <div>). Every article prop is forwarded. The parts read the receipt's size from context, so they render inside a Receipt only; each forwards its element's props and merges className last. receiptVariants is the recipe and ReceiptTone the tone type.

PropTypeDefaultDescription
size"sm" | "md""md"The width and the print size: sm is the 14rem stub a handheld device feeds out (text-xs), md the 20rem ticket a dialog shows (text-sm).
edge"none" | "top" | "bottom" | "both""bottom"Which ends of the paper are torn.
classNamestring-Merged last on the root, where the face, the print size, the width and the --receipt-* roles live. A height or a min-height stretches the paper with it.
Data attributeDescription
data-slot"receipt" on the root, "receipt-paper" on the paper.
data-size"sm" or "md".
data-edgeThe torn ends.
CSS variableDescription
--receipt-paperThe paper's ground.
--receipt-inkThe print.
--receipt-mutedSubtitles, captions, units and the small print.
--receipt-faintThe footer's brand line.
--receipt-ruleThe light 1px rule.
--receipt-rule-strongThe 2px rule of the header and the footer, and the default stamp's edge.
--receipt-toothThe width of one tooth of the torn edge (2em).

ReceiptHeader

The heading block, a <header>: a logo, the title and the subtitle, centred and ruled off underneath with the strong rule. Last on the paper, it drops the rule.

Data attributeDescription
data-slot"receipt-header".

ReceiptTitle

What the slip is ("Breath test", the shop's name), an <h2> in capitals, kept in the print face.

Data attributeDescription
data-slot"receipt-title".

ReceiptSubtitle

A line under the title, a <p>: the issuer, an address, the kind of test.

Data attributeDescription
data-slot"receipt-subtitle".

ReceiptRule

A dashed rule across the paper, a Radix Separator. One at either end of the paper, right under the header or next to another rule folds away.

PropTypeDefaultDescription
variant"light" | "strong""light"1px, or the 2px rule of the header and footer.
decorativebooleantruePrinting, not structure (role="none"). Pass false to expose it as a separator.
orientation"horizontal" | "vertical""horizontal"Forwarded to Radix Separator.
Data attributeDescription
data-slot"receipt-rule".
data-variant"light" or "strong".

ReceiptRow

One line of the slip, a <div>: a label and its value.

PropTypeDefaultDescription
label*React.ReactNode-What the value is ("Subject:", an item), in bold.
childrenReact.ReactNode-The value. It wraps when it runs long, breaking a long code anywhere.
layout"spread" | "inline""spread"spread sets the value at the end of the line, dropping under the label when the two do not fit side by side; inline runs it on after the label.
tone"default" | "success" | "warning" | "destructive" | "info""default"Prints the value bold in that status ink.
Data attributeDescription
data-slot"receipt-row", with "receipt-row-label" and "receipt-row-value" inside.
data-layout"spread" or "inline".

ReceiptFigure

The headline figure, a <div>, centred: a caption, the number and its unit.

PropTypeDefaultDescription
childrenReact.ReactNode-The figure itself.
captionReact.ReactNode-The line above it ("Result"), in small capitals.
unitReact.ReactNode-The line under it ("mg/L of breath").
size"md" | "lg""lg"3em for a short reading, 1.875em for a code that runs longer.
tone"default" | "success" | "warning" | "destructive" | "info""default"Prints the figure in a status ink.
Data attributeDescription
data-slot"receipt-figure", with "receipt-figure-caption", "receipt-figure-value" and "receipt-figure-unit" inside.
data-toneThe tone.

ReceiptStamp

The verdict ("Positive", "Paid"), a <div> boxed and in capitals. A leading icon sits at 1em, inline with the words.

PropTypeDefaultDescription
tone"default" | "success" | "warning" | "destructive" | "info""default"The verdict's ink and tint. default is an outlined box in the ink.
Data attributeDescription
data-slot"receipt-stamp".
data-toneThe tone.

ReceiptNote

The small print, a <div>: plain text, or several ps, which stack.

Data attributeDescription
data-slot"receipt-note".

ReceiptFooter

The brand line at the foot, a <footer>, widely spaced and ruled off above. Several children sit in a row. First on the paper or after a ReceiptRule, it drops its own rule.

Data attributeDescription
data-slot"receipt-footer".

FAQ#

Paper is a document: a contract or a report on a white sheet, in a serif, laid out at one width and scaled as a whole. Receipt is a slip from a printer: a narrow column of monospace lines on cream thermal paper with a torn edge. Use Receipt for what a till, a meter or a handheld device prints.