Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/luis3132/tauri-plugin-thermal-printer/llms.txt

Use this file to discover all available pages before exploring further.

The basic receipt and ticket patterns cover most day-to-day use-cases, but the plugin exposes several more powerful features: a complete catalogue of every section type, document-wide GlobalStyles, paper-size helper functions, test printing with fine-grained control flags, and Android Bluetooth printing. This page explores all of them with realistic, runnable examples.

Complete Builder Showcase

The snippet below builds a single PrintJobRequest using every available builder helper. Use it as a reference when wiring up a new section type — each block is annotated with what it does and why you would reach for it.
import {
  print_thermal_printer,
  type PrintJobRequest,
  title,
  subtitle,
  text,
  line,
  feed,
  cut,
  globalStyles,
  beep,
  drawer,
  table,
  qr,
  barcode,
  dataMatrix,
  pdf417,
  image,
  logo,
  ENCODE,
  TEXT_ALIGN,
  TEXT_SIZE,
  TEXT_FONT,
  BARCODE_TYPE,
  BARCODE_TEXT_POSITION,
  QR_ERROR_CORRECTION,
  IMAGE_MODE,
  CUT_MODE,
} from "tauri-plugin-thermal-printer";

const job: PrintJobRequest = {
  printer: "TM-T20II",
  paper_size: "Mm80",   // 48 chars/line, 576 px wide
  options: {
    code_page: 0,
    encode: ENCODE.ACCENT_REMOVER,
    use_gbk: false,
  },
  sections: [

    // ── 1. GlobalStyles ──────────────────────────────────────────
    // Sets document-wide defaults. Every subsequent Text / Title /
    // Subtitle / Table inherits these values unless they override.
    globalStyles({ align: TEXT_ALIGN.LEFT, font: TEXT_FONT.A }),

    // ── 2. Title ─────────────────────────────────────────────────
    // Forced double-size, centre-aligned by the printer engine.
    title("DEMO STORE"),

    // ── 3. Subtitle ──────────────────────────────────────────────
    // Forced bold + increased line height.
    subtitle("Receipt #A-1001"),

    // ── 4. Plain Text ────────────────────────────────────────────
    text("Date: 2026-03-30  14:22"),
    line("="),

    // ── 5. Table ─────────────────────────────────────────────────
    // column_widths must sum to 48 on Mm80 paper.
    // 6 + 28 + 14 = 48 ✓
    table(
      3,
      [
        [
          text("1"),
          text("Americano"),
          text("$2.50", { align: TEXT_ALIGN.RIGHT }),
        ],
        [
          text("2"),
          text("Croissant"),
          text("$7.00", { align: TEXT_ALIGN.RIGHT }),
        ],
      ],
      {
        column_widths: [6, 28, 14],
        header: [
          text("QTY",   { bold: true }),
          text("ITEM",  { bold: true }),
          text("TOTAL", { bold: true, align: TEXT_ALIGN.RIGHT }),
        ],
        truncate: true,
      },
    ),
    line("-"),

    // ── 6. Bold + double-size total ──────────────────────────────
    text("Grand total: $9.50", {
      bold: true,
      size: TEXT_SIZE.DOUBLE,
      align: TEXT_ALIGN.RIGHT,
    }),

    // ── 7. QR Code ───────────────────────────────────────────────
    // model 2 supports up to 4296 chars at error correction "M".
    qr("https://example.com/r/A-1001", {
      size: 6,
      error_correction: QR_ERROR_CORRECTION.M,
      model: 2,
      align: TEXT_ALIGN.CENTER,
    }),

    // ── 8. Barcode ───────────────────────────────────────────────
    barcode("123456789012", BARCODE_TYPE.EAN13, {
      width: 3,
      height: 70,
      text_position: BARCODE_TEXT_POSITION.BELOW,
      align: TEXT_ALIGN.CENTER,
    }),

    // ── 9. DataMatrix ─────────────────────────────────────────────
    // 2D matrix code; useful when barcode width is constrained.
    dataMatrix("A-1001", 6),

    // ── 10. PDF417 ────────────────────────────────────────────────
    // Stacked 2D barcode popular in boarding passes and IDs.
    pdf417("A-1001|TOTAL=9.50|PAID", {
      columns: 0,        // 0 = auto
      rows: 0,           // 0 = auto
      width: 2,
      height: 3,
      error_correction: 2,
    }),

    // ── 11. Image ────────────────────────────────────────────────
    // Pass a base64-encoded PNG/JPEG.  max_width: 0 = full paper width.
    image("<BASE64_IMAGE_DATA>", {
      max_width: 0,
      align: TEXT_ALIGN.CENTER,
      dithering: true,        // Floyd-Steinberg for better mono output
      size: IMAGE_MODE.NORMAL,
    }),

    // ── 12. Logo ─────────────────────────────────────────────────
    // Prints a logo stored in the printer's NV memory at key_code 1.
    logo(1, IMAGE_MODE.NORMAL),

    // ── 13. Cash Drawer ──────────────────────────────────────────
    drawer(2, 120),   // pin 2, 120 ms pulse

    // ── 14. Beep ─────────────────────────────────────────────────
    beep(1, 3),       // 1 beep, 3 ms duration

    // ── 15. Feed ─────────────────────────────────────────────────
    feed(3),          // advance 3 lines before cut

    // ── 16. Cut ──────────────────────────────────────────────────
    cut(CUT_MODE.FULL, 0),
  ],
};

try {
  await print_thermal_printer(job);
} catch (error) {
  // error is a descriptive string, e.g.:
  // "column_widths sum (45) must equal paper chars_per_line (48)"
  // "QR data length 5000 exceeds maximum 4296 for error correction level 'M'"
  console.error("Print failed:", error);
}

GlobalStyles: Document-Wide Defaults and Per-Section Overrides

GlobalStyles is a regular section — it sets a “current style” state in the print engine that all subsequent Text, Subtitle, and Table cells inherit. Insert a new GlobalStyles section whenever you want to switch modes (e.g., switch to centred alignment for a footer block).
import {
  print_thermal_printer,
  type PrintJobRequest,
  globalStyles,
  title,
  text,
  line,
  feed,
  cut,
  ENCODE,
  TEXT_ALIGN,
  TEXT_SIZE,
  TEXT_FONT,
  CUT_MODE,
} from "tauri-plugin-thermal-printer";

const styledDoc: PrintJobRequest = {
  printer: "TM-T20II",
  paper_size: "Mm80",
  options: { code_page: 0, encode: ENCODE.ACCENT_REMOVER },
  sections: [
    // ── Phase 1: left-aligned body ───────────────────────────────
    globalStyles({ align: TEXT_ALIGN.LEFT, font: TEXT_FONT.A, size: TEXT_SIZE.NORMAL }),
    title("INVOICE #00042"),
    text("Client: Acme Corp"),
    text("Date: 2026-04-01"),
    line("="),

    // Text can override the global style for a single section:
    text("PAID", { bold: true, invert: true, align: TEXT_ALIGN.CENTER }),
    line("="),

    // ── Phase 2: switch to centred for footer ─────────────────────
    globalStyles({ align: TEXT_ALIGN.CENTER, size: TEXT_SIZE.NORMAL }),
    text("Thank you for your business!"),
    text("support@acme.com"),

    // ── Phase 3: small font for legal boilerplate ─────────────────
    globalStyles({ align: TEXT_ALIGN.LEFT, font: TEXT_FONT.B, size: TEXT_SIZE.NORMAL }),
    text("Terms apply. Prices include applicable tax."),
    text("Goods sold are not refundable after 30 days."),

    feed(3),
    cut(CUT_MODE.PARTIAL, 4),
  ],
};

await print_thermal_printer(styledDoc);
GlobalStyles affects only subsequent sections. Sections that appear before it in the array are unaffected. Individual style properties on a Text/Title/Subtitle section temporarily override the global value for that one section only.

Paper Size Helpers

The TypeScript package exports constants and helper functions that mirror the values used inside the Rust backend, so you can calculate column widths programmatically instead of hard-coding them.
import {
  PAPER_SIZE_CHARS_PER_LINE,
  PAPER_SIZE_PIXELS_WIDTH,
  DEFAULT_PAPER_SIZE,
  getPaperSizeCharsPerLine,
  getPaperSizePixelsWidth,
  type PaperSize,
} from "tauri-plugin-thermal-printer";

// The default paper size used when paper_size is not set in PrintJobRequest
console.log(DEFAULT_PAPER_SIZE);                      // "Mm80"

// Lookup via constant map
const size: PaperSize = "Mm58";
console.log(PAPER_SIZE_CHARS_PER_LINE[size]);         // 32
console.log(PAPER_SIZE_PIXELS_WIDTH[size]);           // 384

// Or via helper functions (identical results)
console.log(getPaperSizeCharsPerLine("Mm80"));        // 48
console.log(getPaperSizePixelsWidth("Mm80"));         // 576
Full reference table:
PaperSizeChars / linePixels wide
"Mm40"21256
"Mm44"24288
"Mm58"32384
"Mm72"42512
"Mm80"48576
"Mm104"62752

Dynamic Column Widths

Compute column_widths from the paper size at runtime so the same function works on both 58 mm and 80 mm printers.
import {
  print_thermal_printer,
  type PrintJobRequest,
  type PaperSize,
  getPaperSizeCharsPerLine,
  table,
  text,
  title,
  line,
  feed,
  ENCODE,
  TEXT_ALIGN,
} from "tauri-plugin-thermal-printer";

function buildOrderTable(printer: string, paperSize: PaperSize): PrintJobRequest {
  const chars = getPaperSizeCharsPerLine(paperSize);

  // Proportional column distribution that always sums to `chars`:
  // col0 (qty) = 10 %, col1 (description) = 60 %, col2 (price) = 30 %
  const col0 = Math.floor(chars * 0.10);
  const col2 = Math.floor(chars * 0.30);
  const col1 = chars - col0 - col2; // remainder avoids rounding drift

  return {
    printer,
    paper_size: paperSize,
    options: { code_page: 0, encode: ENCODE.ACCENT_REMOVER },
    sections: [
      title("ORDER SUMMARY"),
      line("="),
      table(
        3,
        [
          [
            text("2"),
            text("Widget Pro"),
            text("$19.98", { align: TEXT_ALIGN.RIGHT }),
          ],
          [
            text("1"),
            text("Gadget Plus"),
            text("$34.99", { align: TEXT_ALIGN.RIGHT }),
          ],
        ],
        {
          column_widths: [col0, col1, col2], // always sums to `chars`
          header: [
            text("QTY",   { bold: true }),
            text("DESC",  { bold: true }),
            text("PRICE", { bold: true, align: TEXT_ALIGN.RIGHT }),
          ],
          truncate: true,
        },
      ),
      line("="),
      feed(3),
    ],
  };
}

// Works on both paper sizes without changing any widths manually:
await print_thermal_printer(buildOrderTable("TM-T20II", "Mm80"));
await print_thermal_printer(buildOrderTable("Star TSP143", "Mm58"));

Test Printing

test_thermal_printer() runs a built-in self-test and is the fastest way to verify that a printer is correctly configured. Every flag is optional — omit flags you do not need.
import {
  test_thermal_printer,
  type TestPrintRequest,
  type PrintJobRequest,
  ENCODE,
} from "tauri-plugin-thermal-printer";

// The printer_info field is a regular PrintJobRequest.
// The sections array is ignored during test printing — pass an empty array.
const baseJob: PrintJobRequest = {
  printer: "TM-T20II",
  paper_size: "Mm80",
  options: {
    code_page: 6,
    encode: ENCODE.WINDOWS_1252,
    use_gbk: false,
  },
  sections: [], // not printed during a test run
};

const testRequest: TestPrintRequest = {
  printer_info: baseJob,

  // ── Content flags ─────────────────────────────────────────────
  include_text: true,           // basic text rendering
  include_text_styles: true,    // bold, underline, inverted text
  include_alignment: true,      // left / centre / right alignment
  include_columns: true,        // multi-column table layout
  include_separators: true,     // Line sections (─── dividers)

  // ── Code symbol flags ─────────────────────────────────────────
  include_barcode: true,        // one CODE128 sample barcode
  include_barcode_types: false, // full barcode type catalogue (slow)
  include_qr: true,             // one QR code sample

  // ── Media flags ───────────────────────────────────────────────
  include_image: false,         // set true + provide image_base64 to test images
  image_base64: null,

  // ── Hardware flags ────────────────────────────────────────────
  include_beep: true,           // acoustic signal test
  test_cash_drawer: false,      // opens cash drawer — set true only if connected
  cut_paper: true,              // full cut at the end of the test
  test_feed: true,              // paper feed test

  // ── Advanced rendering flags ──────────────────────────────────
  test_all_fonts: false,        // prints Font A, B, C samples
  test_invert: false,           // white-on-black text test
  test_rotate: false,           // 90° rotated text test
};

try {
  await test_thermal_printer(testRequest);
  console.log("Test print completed successfully");
} catch (error) {
  console.error("Test print failed:", error);
}
test_thermal_printer returns Promise<void> and throws a string on failure, just like print_thermal_printer. Always wrap calls in try/catch.

Android Bluetooth Printing

On Android the printer field must be the Bluetooth MAC address of the printer (e.g. "AA:BB:CC:DD:EE:FF"). The device must already be paired in the Android Bluetooth settings. Use list_thermal_printers() to discover available Bluetooth printers at runtime.
import {
  list_thermal_printers,
  print_thermal_printer,
  type PrintJobRequest,
  type PrinterInfo,
  title,
  text,
  line,
  feed,
  cut,
  ENCODE,
  TEXT_ALIGN,
  CUT_MODE,
} from "tauri-plugin-thermal-printer";

// ── Step 1: Discover paired Bluetooth printers ────────────────────
let printers: PrinterInfo[] = [];
try {
  printers = await list_thermal_printers();
} catch (error) {
  console.error("Could not list printers:", error);
}

// PrinterInfo returned for Android Bluetooth printers:
// {
//   name: "RPP300",
//   interface_type: "BLUETOOTH",
//   identifier: "AA:BB:CC:DD:EE:FF",   ← use this as `printer`
//   status: "IDLE"
// }

const bluetoothPrinter = printers.find(
  (p) => p.interface_type === "BLUETOOTH",
);

if (!bluetoothPrinter) {
  throw new Error("No paired Bluetooth printer found.");
}

// ── Step 2: Build and send the print job ──────────────────────────
// Use the MAC address (identifier) as the printer field.
const job: PrintJobRequest = {
  printer: bluetoothPrinter.identifier, // e.g. "AA:BB:CC:DD:EE:FF"
  paper_size: "Mm58",                   // common for portable BT printers
  options: {
    code_page: 0,
    encode: ENCODE.ACCENT_REMOVER,
    use_gbk: false,
  },
  sections: [
    title("MOBILE RECEIPT"),
    line("="),
    text("Item: Widget Pro"),
    text("Price: $19.98"),
    line("-"),
    text("TOTAL: $19.98", { bold: true, align: TEXT_ALIGN.CENTER }),
    line("="),
    feed(3),
    cut(CUT_MODE.PARTIAL, 0),
  ],
};

try {
  await print_thermal_printer(job);
} catch (error) {
  console.error("Bluetooth print failed:", error);
}
Android requirements
  • The printer must be paired in Android Bluetooth settings before the app runs — the plugin does not initiate pairing.
  • Bluetooth runtime permissions are requested automatically by the plugin.
  • Network printing is not supported on Android; use BLUETOOTH printers only.
  • iOS is not supported.
If you hard-code a MAC address during development, store it as a user preference or app setting so users can change printers without a rebuild. Use list_thermal_printers() to populate a picker UI and save the chosen identifier to your Tauri store.

Build docs developers (and LLMs) love