Police Report
Breath alcohol test
Result
0.32
mg/L of breath
Legal limit: 0.25 mg/L
Approved ALCO-TEST device
The driver is over the legal alcohol limit.
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.
Breath alcohol test
Result
0.32
mg/L of breath
Legal limit: 0.25 mg/L
Approved ALCO-TEST device
The driver is over the legal alcohol limit.
# One-time setup (tokens + lib helpers)
npx koalaui-cli@latest init
# Add this component (its dependencies come along)
npx koalaui-cli@latest add receiptimport {
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>
)
}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>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.
AFIS · Automated fingerprint system
Fingerprint
Lx482B19Ajk7730
Approved AFIS SCANNER device
The subject is on record in the fingerprint database.
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.
1200 Harbor Way · Bayview
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.
Test taken with an approved ALCO-TEST device.
Legal limit: exceeded
Breath alcohol test
Result
0.32
mg/L of breath
Legal limit: 0.25 mg/L
Approved ALCO-TEST device
The driver is over the legal alcohol limit.
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.
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.
Reading
0.08
mg/L of breath
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.
Breath alcohol test
Result
0.32
mg/L of breath
Legal limit: 0.25 mg/L
Approved ALCO-TEST device
Breath alcohol test
Result
0.32
mg/L of breath
Legal limit: 0.25 mg/L
Approved ALCO-TEST device
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.
The Grand · Bayview
Ticket no.
A-0291
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.
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.
| Prop | Type | Default | Description |
|---|---|---|---|
| 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. |
| className | string | - | 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 attribute | Description |
|---|---|
| data-slot | "receipt" on the root, "receipt-paper" on the paper. |
| data-size | "sm" or "md". |
| data-edge | The torn ends. |
| CSS variable | Description |
|---|---|
| --receipt-paper | The paper's ground. |
| --receipt-ink | The print. |
| --receipt-muted | Subtitles, captions, units and the small print. |
| --receipt-faint | The footer's brand line. |
| --receipt-rule | The light 1px rule. |
| --receipt-rule-strong | The 2px rule of the header and the footer, and the default stamp's edge. |
| --receipt-tooth | The width of one tooth of the torn edge (2em). |
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 attribute | Description |
|---|---|
| data-slot | "receipt-header". |
What the slip is ("Breath test", the shop's name), an <h2> in capitals, kept in the print face.
| Data attribute | Description |
|---|---|
| data-slot | "receipt-title". |
A line under the title, a <p>: the issuer, an address, the kind of test.
| Data attribute | Description |
|---|---|
| data-slot | "receipt-subtitle". |
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.
| Prop | Type | Default | Description |
|---|---|---|---|
| variant | "light" | "strong" | "light" | 1px, or the 2px rule of the header and footer. |
| decorative | boolean | true | Printing, not structure (role="none"). Pass false to expose it as a separator. |
| orientation | "horizontal" | "vertical" | "horizontal" | Forwarded to Radix Separator. |
| Data attribute | Description |
|---|---|
| data-slot | "receipt-rule". |
| data-variant | "light" or "strong". |
One line of the slip, a <div>: a label and its value.
| Prop | Type | Default | Description |
|---|---|---|---|
| label* | React.ReactNode | - | What the value is ("Subject:", an item), in bold. |
| children | React.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 attribute | Description |
|---|---|
| data-slot | "receipt-row", with "receipt-row-label" and "receipt-row-value" inside. |
| data-layout | "spread" or "inline". |
The headline figure, a <div>, centred: a caption, the number and its unit.
| Prop | Type | Default | Description |
|---|---|---|---|
| children | React.ReactNode | - | The figure itself. |
| caption | React.ReactNode | - | The line above it ("Result"), in small capitals. |
| unit | React.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 attribute | Description |
|---|---|
| data-slot | "receipt-figure", with "receipt-figure-caption", "receipt-figure-value" and "receipt-figure-unit" inside. |
| data-tone | The tone. |
The verdict ("Positive", "Paid"), a <div> boxed and in capitals. A leading icon sits at 1em, inline with the words.
| Prop | Type | Default | Description |
|---|---|---|---|
| tone | "default" | "success" | "warning" | "destructive" | "info" | "default" | The verdict's ink and tint. default is an outlined box in the ink. |
| Data attribute | Description |
|---|---|
| data-slot | "receipt-stamp". |
| data-tone | The tone. |
The small print, a <div>: plain text, or several ps, which stack.
| Data attribute | Description |
|---|---|
| data-slot | "receipt-note". |
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 attribute | Description |
|---|---|
| data-slot | "receipt-footer". |