retail-print-kit

Design receipt and label templates visually, then print them from Node.js

Hard-coding a receipt as a chain of text() calls means a code change every time a store wants a different footer. A template moves the layout into JSON that your app stores and edits.

Open the designer to build one in the browser: add blocks, edit properties, see the live preview against sample data, and export JSON. It runs entirely in the page; nothing is uploaded.

A receipt template

const template = {
  name: 'receipt', version: 1,
  blocks: [
    { type: 'text', value: '{{store.name | upper}}', align: 'center', style: 'b', size: [2, 2] },
    { type: 'text', value: '{{date | date:datetime}}   #{{id}}', align: 'center' },
    { type: 'line' },
    { type: 'table', rows: 'items', columns: [
      { value: '{{name}}', header: 'Item', width: 0.6 },
      { value: '{{qty}}', header: 'Qty', width: 0.1, align: 'CENTER' },
      { value: '{{total | money:$}}', header: 'Amount', width: 0.3, align: 'RIGHT' },
    ] },
    { type: 'line' },
    { type: 'row', cells: [{ value: 'TOTAL', width: 0.7 }, { value: '{{total | money:$}}', width: 0.3, align: 'RIGHT' }] },
    { type: 'if', when: 'customer', blocks: [{ type: 'text', value: 'Thank you, {{customer.name}}!' }],
      else: [{ type: 'text', value: 'Thank you!' }] },
    { type: 'each', items: 'notes', blocks: [{ type: 'text', value: '* {{this}}' }] },
    { type: 'qr', value: 'https://example.com/r/{{id}}', align: 'center' },
    { type: 'cut' },
    { type: 'drawer' },
  ],
};
const { Printer, profiles } = require('retail-print-kit');
const { NetTransport } = require('retail-print-kit/net');

const printer = new Printer(new NetTransport('192.168.1.50'), profiles['epson-tm-t88']);
await printer.open();
printer.render(template, {
  id: 'A1042', date: new Date(), store: { name: 'My Store' },
  items: [{ name: 'Coffee', qty: 2, total: 5 }], total: 5, notes: ['No refunds on food'],
});
await printer.close();

The same template fits 80 mm and 58 mm paper, because column widths are fractions of the line and the profile supplies the column count.

Blocks

BlockPurpose
textA line with align, style, size, font
lineA rule across the paper
rowOne line split into cells
tableA header and one row per item of an array
imageA logo or picture
qr, barcodeCodes with placeholders in the value
eachRepeat blocks for each item of an array
ifShow blocks when a value is present, with optional else
feed, newline, cut, drawerPaper and drawer control

Placeholders and filters

{{path}} reads from the data, with dots for nesting. Inside each and table, {{this}}, {{@index}} and {{@number}} refer to the current item.

FilterExampleResult
money{{total | money:$}}$12.50
fixed{{weight | fixed:3}}1.250
upper, lower, trim{{name | upper}}COFFEE
date{{date | date:datetime}}local date and time
default{{note | default:none}}none when empty
pad, padEnd{{qty | pad:3}}right-aligned in 3 columns
count{{items | count}}number of items

Preview in your own app

const { render, opsToHtml, profiles } = require('retail-print-kit');
const html = opsToHtml(render(template, data, profiles['epson-tm-t88']), profiles['epson-tm-t88']);

In the browser import from retail-print-kit/browser.

Label templates

The designer has a label mode with drag-to-position: open it, and see printing labels.

From the command line

npx retail-print-kit print --template receipt.json --data sale.json --net 192.168.1.50
npx retail-print-kit print --template receipt.json --data sale.json --out preview.html

Install

npm install retail-print-kit

All guides · Designer · npm · GitHub