npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

zpl-fluent-api

v2.3.0

Published

Design beautiful labels for Zebra printers without the headache of cryptic ZPL commands. Use real-world measurements (inches/mm) instead of counting dots.

Readme

Zebra Printer Templating API 🏷️

Design beautiful labels for Zebra printers without the headache of cryptic ZPL commands. Use real-world measurements (inches/mm) instead of counting dots!

npm version TypeScript License

✨ Why Zebra Printer Templating API?

Writing raw ZPL code is painful. You have to:

  • Manually convert inches to dots based on printer DPI
  • Memorize cryptic commands like ^FO150,300^BCN,225,Y,N,A
  • Debug by trial and error
  • No type safety or autocomplete

Zebra Printer Templating API solves all of this:

// ❌ Old way (cryptic ZPL)
const zpl = '^XA^FO150,150^A0N,75,75^FDASSET TAG^FS^FO150,300^BCN,225,Y,N,A^FD12345^FS^XZ';

// ✅ New way (fluent & readable)
const zpl = new ZebraBuilder(300)
  .origin(0.5, 0.5)        // Position in inches
  .font('0', 0.25)         // Font with real height
  .text('ASSET TAG')
  .origin(0.5, 1.0)
  .barcode128('12345', 0.75)  // Barcode with readable height
  .render();

🚀 Quick Start

Installation

npm install zpl-fluent-api

Your First Label

import { ZebraBuilder } from 'zpl-fluent-api';

// Create a simple asset tag label
const zpl = new ZebraBuilder(300)  // 300 DPI printer
  .origin(0.5, 0.5)               // 0.5" from left, 0.5" from top
  .font('0', 0.25)                // Font 0, 0.25" height
  .text('ASSET TAG')
  .origin(0.5, 1.0)               // Move to next position
  .barcode128('12345', 0.75)      // Code 128 barcode, 0.75" height
  .render();

console.log(zpl);
// Output: ^XA^FO150,150^A0N,75,75^FDASSET TAG^FS^FO150,300^BCN,225,Y,N,A^FD12345^FS^XZ

Preview in Browser

const previewUrl = new ZebraBuilder(300)
  .origin(0.5, 0.5)
  .font('0', 0.25)
  .text('ASSET TAG')
  .origin(0.5, 1.0)
  .barcode128('12345', 0.75)
  .preview();

console.log(`Open this URL to preview: ${previewUrl}`);
// Opens Labelary viewer in your browser!

📚 Features

  • 🎯 DPI-Aware - Automatic conversion from inches/mm to printer dots
  • 🔗 Fluent Interface - Chain methods for intuitive label design
  • 🛡️ Type Safety - Full TypeScript support with comprehensive types
  • ✅ Validation - Built-in text validation for ZPL compatibility
  • 👁️ Preview Integration - Instant browser preview via Labelary
  • 🏭 Production Ready - Comprehensive error handling
  • 📊 37+ ZPL Commands - All major template-building commands
  • 🔢 10+ Barcode Types - Code 128, Code 39, QR, Data Matrix, Aztec, EAN, UPC, and more
  • 🎨 Advanced Graphics - Boxes, circles, ellipses, diagonal lines, and images
  • ⚙️ Label Configuration - Length, width, quantity, orientation, and more

📖 API Reference

Constructor

new ZebraBuilder(dpi?: number)

Parameters:

  • dpi - Printer DPI (dots per inch). Default: 203

Common DPI values:

  • 150 (6 dpmm) - Low resolution
  • 203 (8 dpmm) - Standard (default)
  • 300 (12 dpmm) - High resolution
  • 600 (24 dpmm) - Ultra high resolution

📍 Positioning & Text

origin(x, y, unit?)

Sets the field position (ZPL ^FO command).

.origin(1.0, 2.0)           // 1" from left, 2" from top
.origin(25, 50, 'mm')       // 25mm from left, 50mm from top

font(name, height, unit?, width?, orientation?)

Sets font properties (ZPL ^A command).

.font('0', 0.25)                    // Font 0, 0.25" height
.font('A', 12, 'mm')                // Font A, 12mm height
.font('0', 0.3, 'in', 0.25, 'R')    // Font 0, 0.3" height × 0.25" width, rotated 90°

text(content)

Adds text content (ZPL ^FD command).

.text('Hello World')        // Normal text

fieldPosition(x, y, unit?)

Alternative field positioning (ZPL ^FT command).

.fieldPosition(1.0, 2.0)     // 1" from left, 2" from top

🔢 Barcodes

barcode128(data, height, opts?)

Code 128 barcode (ZPL ^BC command).

.barcode128('123456789', 0.75)                    // Standard
.barcode128('ABC123', 15, 'mm', { printText: false })  // No text
.barcode128('DATA', 0.5, 'in', { printText: true, textAbove: true })

barcode39(data, height, opts?)

Code 39 barcode (ZPL ^B3 command).

.barcode39('ABC123', 0.5)                    // Standard
.barcode39('DATA', 15, 'mm', { printText: false })
.barcode39('DATA', 0.5, 'in', { checkDigit: true })

qr_code(data, opts?)

QR Code (ZPL ^BQ command).

.qr_code('https://example.com')                    // Standard
.qr_code('DATA', { magnification: 3, errorCorrection: 'H' })

dataMatrix(data, height, opts?)

Data Matrix (ZPL ^BX command).

.dataMatrix('DATA123', 100, { unit: 'dots', qualityLevel: 200 })

aztec(data, opts?)

Aztec barcode (ZPL ^BO command).

.aztec('DATA123', { magnification: 5 })

barcode93(data, height, opts?)

Code 93 barcode (ZPL ^BA command).

.barcode93('ABC123', 0.5)

interleaved2of5(data, height, opts?)

Interleaved 2 of 5 (ZPL ^BD command).

.interleaved2of5('12345', 0.75)

ean13(data, height, opts?)

EAN-13 barcode (ZPL ^BE command).

.ean13('123456789012', 0.75)

upcA(data, height, opts?)

UPC-A barcode (ZPL ^BU command).

.upcA('123456789012', 0.75)

codabar(data, height, opts?)

Codabar barcode (ZPL ^BK command).

.codabar('A123456B', 0.5)

🎨 Shapes & Graphics

box(width, height, opts?)

Draws a box/rectangle (ZPL ^GB command).

.box(4, 2)                           // 4" × 2" box
.box(100, 50, { unit: 'mm', thickness: 3 })
.box(2, 1, { unit: 'in', color: 'B', rounding: 3 })

diagonalLine(xEnd, yEnd, opts?)

Draws a diagonal line (ZPL ^GD command).

.diagonalLine(100, 100)                    // Diagonal line
.diagonalLine(50, 75, { unit: 'mm', thickness: 2, color: 'W' })

circle(diameter, opts?)

Draws a circle (ZPL ^GC command).

.circle(50)                                // 50" diameter
.circle(25, { unit: 'mm', thickness: 2, color: 'W' })

ellipse(horizontalDiameter, verticalDiameter, opts?)

Draws an ellipse (ZPL ^GE command).

.ellipse(100, 50)                          // 100" × 50" ellipse
.ellipse(50, 25, { unit: 'mm', thickness: 2 })

graphicField(data, width, height, format?)

Graphic field from hex data (ZPL ^GF command).

.graphicField('48484848484848', 10, 10)     // ASCII hex
.graphicField('DATA', 10, 10, 'B')          // Binary format

recallGraphic(name, x, y, unit?)

Recall stored graphic (ZPL ^XG command).

.recallGraphic('LOGO', 0.5, 0.5)

⚙️ Configuration

labelLength(length, unit?)

Sets label length (ZPL ^LL command).

.labelLength(4, 'in')              // 4 inch label
.labelLength(100, 'mm')            // 100mm label

labelWidth(width, unit?)

Sets label width (ZPL ^PW command).

.labelWidth(6, 'in')               // 6 inch width

printQuantity(quantity, opts?)

Sets print quantity (ZPL ^PQ command).

.printQuantity(10)                 // Print 10 labels
.printQuantity(5, { copies: 2, pause: 500 })

printOrientation(orientation?)

Changes print orientation (ZPL ^PO command).

.printOrientation('I')             // Invert orientation
.printOrientation('N')             // Normal

mirror(enabled?)

Mirrors label output (ZPL ^PM command).

.mirror(true)                      // Mirror label
.mirror(false)                     // Normal

characterEncoding(encoding, sourceEncoding?)

Sets character encoding (ZPL ^CI command).

.characterEncoding(28)             // UTF-8
.characterEncoding(28, 850)        // UTF-8 with CP-850 source

defaultFont(name, height, opts?)

Sets default font (ZPL ^CF command).

.defaultFont('0', 30, { unit: 'mm', width: 25, orientation: 'R' })

defaultOrientation(orientation?)

Sets default field orientation (ZPL ^FW command).

.defaultOrientation('N')           // Normal
.defaultOrientation('R')           // Rotated 90°

🔧 Field Options

fieldReverse()

Reverses field colors (ZPL ^FR command).

.fieldReverse()                    // White text on black

fieldBlock(width, maxLines, secondaryParameter, justification, hangingIndent)

Multi-line text block (ZPL ^FB command).

.fieldBlock(200, 5, 0, 'L', 0)

fieldNumber(fieldNumber, opts?)

Named field (ZPL ^FN command).

.fieldNumber(1)
.fieldNumber(2, { formatNumber: 100 })

fieldVariable(fieldNumber, opts?)

Variable field (ZPL ^FV command).

.fieldVariable(1)

fieldExtraction(sourceField, startPosition, length, opts?)

Data extraction (ZPL ^FE command).

.fieldExtraction(1, 0, 10)

escapeCharacter(escape)

Sets escape character (ZPL ^FH command).

.escapeCharacter('_')              // Use underscore as escape

fieldHex()

Enables hex mode (ZPL ^FH command).

.fieldHex()

comment(text)

Adds comment (ZPL ^FX command).

.comment('This is a comment')

🏷️ Label Settings

labelHome(x, y)

Sets label home position (ZPL ^LH command).

.labelHome(10, 10)

labelShift(shift)

Shifts label position (ZPL ^LS command).

.labelShift(10)

mediaTracking(mode?)

Sets media tracking (ZPL ^MN command).

.mediaTracking('A')                // Advanced tracking
.mediaTracking('N')                // No tracking

barcodeDefaults(moduleWidth, opts?)

Sets barcode defaults (ZPL ^BY command).

.barcodeDefaults(3, { wideToNarrowRatio: 2.5, height: 80 })

downloadFormat(name, data)

Downloads format to memory (ZPL ^DF command).

.downloadFormat('TEMPLATE', '^XA^FO100,100^FDTEMPLATE^FS^XZ')

recallFormat(name)

Recalls format from memory (ZPL ^XF command).

.recallFormat('TEMPLATE')

🛠️ Utility Methods

render()

Returns the complete ZPL code.

const zpl = builder.render();

preview(labelWidth?, labelHeight?)

Generates a Labelary preview URL.

const url = builder.preview();              // Default 4×6 inch
const url = builder.preview(3, 2);         // 3×2 inch label

getDPI()

Returns the current DPI setting.

const dpi = builder.getDPI(); // 300

getCurrentPosition()

Returns current position in dots.

const pos = builder.getCurrentPosition(); // {x: 150, y: 300}

💡 Examples

🏷️ Product Label

const productLabel = new ZebraBuilder(300)
  .characterEncoding(28)                    // UTF-8 encoding
  .barcodeDefaults(2, { wideToNarrowRatio: 3, height: 80 })
  .box(2, 1, { thickness: 3 })              // Border box
  .origin(0.1, 0.1)
  .defaultFont('0', 0.12, { unit: 'in' })
  .text('PRODUCT')
  .origin(0.1, 0.3)
  .qr_code('https://example.com/product/123', { magnification: 4, errorCorrection: 'M' })
  .origin(0.1, 0.5)
  .barcode39('ABC123', 0.4, { unit: 'in', printText: true, checkDigit: true })
  .origin(1.5, 0.8)
  .font('0', 0.15, { unit: 'in', width: 0.15, orientation: 'R' })
  .fieldReverse()
  .text('$29.99')
  .printQuantity(1)
  .comment('End of label')
  .render();

📊 Multi-Barcode Label

const multiBarcodeLabel = new ZebraBuilder(203)
  .origin(0.25, 0.25)
  .font('0', 0.15)
  .text('MULTI-BARCODE EXAMPLE')
  .origin(0.25, 0.5)
  .qr_code('https://example.com', { magnification: 3, errorCorrection: 'H' })
  .origin(0.25, 1.0)
  .dataMatrix('DATA123', 100, { unit: 'dots', qualityLevel: 200, columns: 24, rows: 24 })
  .origin(0.25, 1.5)
  .aztec('AZTEC123', { magnification: 5, eci: true, size: 15 })
  .origin(0.25, 2.0)
  .circle(50, { thickness: 2 })
  .render();

🎨 Graphic-Intensive Label

const graphicLabel = new ZebraBuilder(300)
  .box(4, 3, { thickness: 3 })
  .origin(0.1, 0.1)
  .circle(30, { thickness: 2 })
  .origin(0.5, 0.1)
  .diagonalLine(100, 50, { thickness: 2 })
  .origin(0.1, 0.5)
  .font('0', 0.12)
  .fieldReverse()
  .text('GRAPHIC LABEL')
  .origin(0.1, 0.8)
  .font('0', 0.08)
  .text('with shapes and graphics')
  .origin(0.1, 1.2)
  .graphicField('48484848484848', 20, 10)
  .origin(0.1, 1.8)
  .barcode128('GRAPHIC123', 0.5)
  .mirror(true)
  .render();

📏 Metric Units

const metricLabel = new ZebraBuilder(203)
  .origin(10, 10, 'mm')      // 10mm from edges
  .font('0', 5, { unit: 'mm' })
  .text('METRIC LABEL')
  .origin(10, 20, 'mm')
  .barcode128('987654321', 15, { unit: 'mm' })
  .box(90, 50, { unit: 'mm', thickness: 2 })
  .render();

🏪 Retail Label with EAN-13

const retailLabel = new ZebraBuilder(300)
  .origin(0.25, 0.25)
  .font('0', 0.2)
  .text('PREMIUM COFFEE')
  .origin(0.25, 0.5)
  .ean13('123456789012', 0.75, { printText: true })
  .origin(0.25, 1.0)
  .font('0', 0.15)
  .text('$12.99')
  .origin(2.5, 0.5)
  .qr_code('https://shop.example.com/coffee', { magnification: 5 })
  .render();

🎯 DPI Support

The library automatically converts your measurements to dots based on your printer's DPI:

| DPI | dpmm | Use Case | |-----|------|----------| | 150 | 6 | Low resolution, draft printing | | 203 | 8 | Standard thermal printers (default) | | 300 | 12 | High resolution, detailed labels | | 600 | 24 | Ultra high resolution, small text |

// All of these produce the same physical size on their respective printers
new ZebraBuilder(203).origin(1, 1)     // 203 dots
new ZebraBuilder(300).origin(1, 1)     // 300 dots
new ZebraBuilder(600).origin(1, 1)     // 600 dots

⚠️ Error Handling

The library includes built-in validation to catch common mistakes:

try {
  const builder = new ZebraBuilder(300);
  builder.text('Valid text');
  const zpl = builder.render();
} catch (error) {
  console.error('ZPL Error:', error.message);
}

Common errors caught:

  • Invalid DPI values
  • Unsupported characters in text
  • Invalid orientation values

👁️ Browser Preview

The preview() method generates URLs that work with Labelary's online ZPL viewer:

const url = builder.preview();
// Opens: http://labelary.com/viewer.html?zpl=^XA^FO100^FDHello^FS^XZ

// Custom label size
const customUrl = builder.preview(3, 2);  // 3×2 inch label

Just open the URL in your browser to see your label rendered instantly!


🛡️ TypeScript Support

Full TypeScript definitions included for excellent autocomplete and type safety:

import { ZebraBuilder } from 'zpl-fluent-api';

const builder: ZebraBuilder = new ZebraBuilder(300);
const url: string = builder.preview();

All options interfaces are fully typed:

const opts: Barcode128Options = {
  printText: true,
  textAbove: false,
  orientation: 'N',
  checkDigit: false,
  mode: 'A'
};

🤝 Contributing

We welcome contributions! Here's how to help:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Add tests for new functionality
  4. Ensure all tests pass (npm test)
  5. Submit a pull request

📄 License

MIT License - see LICENSE file for details.


🙏 Acknowledgments

  • Built for developers who love clean, readable code
  • Inspired by the need to make ZPL accessible to everyone
  • Thanks to Zebra Technologies for the ZPL specification

📞 Support


Made with ❤️ for label designers everywhere