About
Thermal receipt printer that feeds any receipt out of its slot in 12px steps, with body shake, skip, haptics and reduced-motion support.
Built with React and Tailwind. Copy the prompt and paste it into Claude Code, Cursor or Lovable: your agent adds Receipt Printer to your project and fits it to your theme.
Code
How Receipt Printer is used: the demo's code. The component's own source comes with a free account.
Usage.tsx
"use client";
import { ReceiptPrinter } from "@/components/ui/receipt-printer";
const people = [
{ name: "Evan", item: "1/2 Nasi goreng", subtotal: 40000 },
{ name: "Dita", item: "1/2 Nasi goreng", subtotal: 40000 },
{ name: "Rio", item: "Sate ayam", subtotal: 50000 },
];
const amount = (value: number) =>
new Intl.NumberFormat("id-ID", { style: "currency", currency: "IDR", maximumFractionDigits: 0 }).format(value);
const total = (subtotal: number) => subtotal * 1.05 * 1.1;
export default function Demo() {
return (
<div className="flex min-h-screen w-full justify-center bg-background px-4 py-10">
<ReceiptPrinter className="w-full max-w-[420px]">
<header className="thermal-header">
<span className="thermal-mark" aria-hidden="true" />
<h3>Patungan</h3>
<p className="thermal-place">Dinner</p>
<div className="thermal-meta">
<span>Date</span>
<span>Oct 12, 2026 · 7:30 PM</span>
</div>
<div className="thermal-divider thermal-divider-double" aria-hidden="true" />
</header>
{people.map((person) => (
<section key={person.name} className="thermal-person">
<h4>{person.name}</h4>
<div className="thermal-column-labels">
<span>Item</span>
<span>Qty</span>
<span>Amount</span>
</div>
<div className="thermal-item">
<span title={person.item}>
{person.item.startsWith("1/2 ") ? (
<>
<span className="thermal-fraction">1/2 </span>
{person.item.slice(4)}
</>
) : (
person.item
)}
</span>
<span className="thermal-qty">1</span>
<span>{amount(person.subtotal)}</span>
</div>
<div className="thermal-breakdown">
<div className="thermal-line thermal-secondary">
<span>Subtotal</span>
<i />
<span>{amount(person.subtotal)}</span>
</div>
<div className="thermal-line thermal-secondary">
<span>Service 5%</span>
<i />
<span>{amount(person.subtotal * 0.05)}</span>
</div>
<div className="thermal-line thermal-secondary">
<span>Tax 10%</span>
<i />
<span>{amount(person.subtotal * 1.05 * 0.1)}</span>
</div>
<p className="thermal-note">Tax not included — added on top of menu prices</p>
</div>
<div className="thermal-line thermal-total">
<span>Total</span>
<i />
<span className="thermal-person-amount">{amount(total(person.subtotal))}</span>
</div>
</section>
))}
<footer className="thermal-footer">
<div className="thermal-divider" aria-hidden="true" />
<div className="thermal-line thermal-grand-total">
<span>Grand total</span>
<i />
<span className="thermal-amount">
{amount(people.reduce((sum, person) => sum + total(person.subtotal), 0))}
</span>
</div>
<div className="thermal-meta">
<span>Paid by</span>
<span className="thermal-payer">Evan</span>
</div>
<div className="thermal-divider thermal-divider-double" aria-hidden="true" />
<div className="thermal-meta">
<span>Receipt</span>
<span className="thermal-receipt-id">#DEMO-012</span>
</div>
<p className="thermal-thanks">
Thank you
<br />
See you at the next meal.
</p>
</footer>
</ReceiptPrinter>
</div>
);
}
