The code of the preview above.
demos/receipt.qwe
view ReceiptDemo() = <div.demo-row style="align-items: flex-start; gap: 28px"> <Receipt id="receipt-demo-cafe" store="Corner Café" address="12 Bridge Street, Porto" phone="+351 22 000 0000" number="0042" date="2026-10-28T09:14:00" cashier="Rui" table="4" currency="€" lines={[{ name: "Flat white", qty: 2, unit: "3.50", amount: "7.00" }, { name: "Croissant", amount: "2.80" }, { name: "Orange juice", qty: 1, amount: "3.20" }]} subtotal="13.00" discount="−1.30" tax="1.17" tax_label="VAT 10%" tip="1.00" total="13.87" paid={[{ method: "Cash", amount: "20.00" }]} change="6.13" footer="Thank you, come again\nWi-Fi: cornercafe / espresso" code="ORD-20261028-0042"/> <Receipt id="receipt-demo-min" store="Kiosk" date="2026-10-28" lines={[{ name: "Newspaper", amount: "$2.50" }]} total="$2.50"/> </div>
ui/receipt.qwe
import ui/theme.qwe use ui_clslet receipt_css = css`.ui-receipt { position: relative; width: 300px; max-width: 100%; margin: 0; padding: 22px 18px 30px; background: var(--ui-surface); color: var(--ui-fg); font: 12.5px/1.5 var(--ui-mono); box-shadow: var(--ui-shadow); border-radius: 2px 2px 0 0; }.ui-receipt::after { content: ""; position: absolute; left: 0; right: 0; bottom: -8px; height: 8px; background: linear-gradient(135deg, var(--ui-surface) 50%, transparent 50%) 0 0 / 12px 8px repeat-x, linear-gradient(45deg, transparent 50%, var(--ui-surface) 50%) 0 0 / 12px 8px repeat-x; }.ui-receipt-head { margin: 0 0 12px; text-align: center; }.ui-receipt-store { font-size: 16px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; }.ui-receipt-head p { margin: 0; color: var(--ui-muted); }.ui-receipt-meta { display: grid; grid-template-columns: auto 1fr; gap: 0 10px; margin: 0; padding: 8px 0; border-top: 1px dashed var(--ui-strong); border-bottom: 1px dashed var(--ui-strong); }.ui-receipt-meta dt { color: var(--ui-muted); }.ui-receipt-meta dd { margin: 0; text-align: right; }.ui-receipt-lines { width: 100%; margin: 8px 0; border-collapse: collapse; }.ui-receipt-lines td { padding: 2px 0; vertical-align: top; }.ui-receipt-lines .ui-receipt-amt { text-align: right; white-space: nowrap; padding-left: 10px; }.ui-receipt-qty { color: var(--ui-muted); }.ui-receipt-totals { display: grid; grid-template-columns: 1fr auto; gap: 2px 10px; margin: 0; padding: 8px 0; border-top: 1px dashed var(--ui-strong); }.ui-receipt-totals dt { color: var(--ui-muted); }.ui-receipt-totals dd { margin: 0; text-align: right; }.ui-receipt-total dt, .ui-receipt-total dd { font-size: 15px; font-weight: 700; color: var(--ui-fg); padding-top: 4px; }.ui-receipt-paid { border-top: 1px dashed var(--ui-strong); }.ui-receipt-foot { margin: 10px 0 0; padding-top: 10px; border-top: 1px dashed var(--ui-strong); text-align: center; white-space: pre-line; }.ui-receipt-code { display: grid; justify-items: center; gap: 6px; margin-top: 12px; text-align: center; letter-spacing: .08em; }.ui-receipt-code:empty { display: none; }@media print { .ui-receipt { box-shadow: none; background: #fff; color: #000; } }`let receipt_months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]fn receipt_date(d) -> str { let s = str(d) let p = split(slice(s, 0, 10), "-") if len(p) != 3 || int(p[1]) == null || int(p[2]) == null { return s } let day = `${int(p[2])} ${receipt_months[int(p[1]) - 1]} ${p[0]}` len(s) >= 16 && (s[10] == "T" || s[10] == " ") ? `${day}, ${slice(s, 11, 16)}` : day}view Receipt(store: str, address: str? = null, phone: str? = null, number: str? = null, date = null, cashier: str? = null, table: str? = null, lines: list = [], subtotal: str? = null, discount: str? = null, tax: str? = null, tax_label: str = "Tax", tip: str? = null, total: str? = null, paid: list = [], change: str? = null, footer: str? = null, code: str? = null, currency: str = "", id: str? = null, class: str? = null, children) { style global receipt_css let amt = (a) => a == null ? "" : starts_with(str(a), "−") || starts_with(str(a), "-") ? `${str(a)[0]}${currency}${slice(str(a), 1, len(str(a)))}` : `${currency}${a}` <article class={ui_cls(["ui-receipt", class])} id={id} aria-label={`Receipt${number != null ? " " + number : ""} from ${store}`}> <header.ui-receipt-head> <div.ui-receipt-store>{store}</div> {address != null && <p>{address}</p>} {phone != null && <p>{phone}</p>} </header> {(number != null || date != null || cashier != null || table != null) && <dl.ui-receipt-meta> {date != null && [<dt>Date</dt>, <dd><time datetime={str(date)}>{receipt_date(date)}</time></dd>]} {number != null && [<dt>Receipt</dt>, <dd>{number}</dd>]} {cashier != null && [<dt>Served by</dt>, <dd>{cashier}</dd>]} {table != null && [<dt>Table</dt>, <dd>{table}</dd>]} </dl>} <table.ui-receipt-lines> <tbody> {for [i, l] in enumerate(lines) => <tr key={i}> <td>{l.qty != null && <span.ui-receipt-qty>{l.qty} × </span>}{l.name}{l.unit != null && <span.ui-receipt-qty> @ {amt(l.unit)}</span>}</td> <td.ui-receipt-amt>{amt(l.amount)}</td> </tr>} </tbody> </table> {(subtotal != null || total != null) && <dl.ui-receipt-totals> {subtotal != null && [<dt>Subtotal</dt>, <dd>{amt(subtotal)}</dd>]} {discount != null && [<dt>Discount</dt>, <dd>{amt(discount)}</dd>]} {tax != null && [<dt>{tax_label}</dt>, <dd>{amt(tax)}</dd>]} {tip != null && [<dt>Tip</dt>, <dd>{amt(tip)}</dd>]} {total != null && <div.ui-receipt-total style="display: contents"><dt>Total</dt><dd>{amt(total)}</dd></div>} </dl>} {len(paid) > 0 && <dl.ui-receipt-totals.ui-receipt-paid> {for [i, p] in enumerate(paid) => [<dt key={`m${i}`}>{p.method}</dt>, <dd key={`a${i}`}>{amt(p.amount)}</dd>]} {change != null && [<dt>Change</dt>, <dd>{amt(change)}</dd>]} </dl>} {footer != null && <p.ui-receipt-foot>{footer}</p>} <div.ui-receipt-code>{children}{code != null && <span>{code}</span>}</div> </article>}