ZPL Language & Preview
A self-contained VS Code extension for editing and previewing Zebra Programming Language (ZPL) labels. Renders fully offline using HTML canvas + bwip-js for barcodes — no network calls, no labelary.com dependency, no cloud round-trip when handling sensitive label data.
If you write or maintain ZPL — for retail, logistics, healthcare, or anything else printed on Zebra hardware — this extension gets you a tight edit-preview-print loop without leaving VS Code.

Features
- Syntax highlighting for
.zpl, .prn, .lbl files (TextMate grammar).
- Live preview in a side panel — updates 150 ms after each keystroke.
- Snippets for common patterns:
label, field, box, code128, qr, fx.
- Configurable printer DPMM (203 / 300 / 600 dpi), label dimensions, ink / background color, zoom — from the preview toolbar or
settings.json.
- Export to PDF at the label's physical size.
- Send to network printer over raw TCP (port 9100 / JetDirect by default).
- Tolerant parsing: ZDesigner-style preamble (
CT~~CD,~CC^~CT~) before ^XA is automatically stripped, so files saved from Zebra Designer just work.
- Pan / zoom in the preview (toolbar buttons or Ctrl/Cmd + scroll).
- Fully offline — no telemetry, no external services, no labelary fallback. Safe for air-gapped or PHI-bearing environments.
Supported ZPL commands
| Category |
Commands |
| Format |
^XA, ^XZ, ^FS, ^FX, ^LH, ^PW, ^LL, ^CC/^CT/^CD, ^CI, ^FH |
| Position |
^FO, ^FT |
| Text |
^A, ^A@, ^CF, ^FD, ^FB, ^FR, ^FW |
| Shapes |
^GB, ^GC, ^GD, ^GE |
| Graphics |
^GF — ASCII hex (format A, with RLE expansion), :Z64: (deflate-compressed base64, decoded via pako), and :B64: (raw base64). Raw binary ^GFB / ^GFC not supported. |
| Barcode defaults |
^BY |
| Barcodes |
^BC (Code 128), ^BQ (QR), ^BX (Data Matrix), ^B3 (Code 39), ^B7 (PDF417), ^BE (EAN-13), ^BU (UPC-A), ^BK (Codabar), ^BA (Code 93), ^BD (MaxiCode) |
Quick start
- Install ZPL Language & Preview from the marketplace.
- Open or create a file with extension
.zpl, .prn, or .lbl (or set the language to "ZPL" via the status-bar mode picker).
- Click the preview icon in the editor title bar (or Cmd+Shift+P → ZPL: Open Preview to the Side).
- Edit. The preview tracks your changes live.
To send a label to a real printer:
- Set
zpl.printer.address in settings.json to your printer's IP (e.g. "192.168.1.50" or "192.168.1.50:9100").
- The preview toolbar's Print button will stream the current document over raw TCP.
Settings
| Setting |
Default |
What it does |
zpl.preview.dpmm |
8 |
Printer resolution: 6 (152 dpi), 8 (203 dpi), 12 (300 dpi), or 24 (600 dpi). |
zpl.preview.labelWidthMm |
101.6 |
Label width in mm (default 4 inches). |
zpl.preview.labelHeightMm |
152.4 |
Label height in mm (default 6 inches). |
zpl.preview.backgroundColor |
#ffffff |
Simulated label background color. |
zpl.preview.inkColor |
#000000 |
Simulated ink color. |
zpl.preview.zoom |
1 |
Initial zoom factor for the preview. |
zpl.printer.address |
"" |
Default network printer (host or host:port; port defaults to 9100). |
zpl.printer.timeoutMs |
5000 |
TCP connect timeout for sending labels. |
All preview-related settings can also be tweaked from the toolbar inside the preview panel — useful for scratch experimentation without touching settings.json.
Commands
| Command |
Default |
ZPL: Open Preview |
open preview in the active column |
ZPL: Open Preview to the Side |
open preview in a side column (most common) |
Both commands are also exposed as the preview icon in the editor title bar whenever a .zpl / .prn / .lbl file is active.
Why offline?
A lot of ZPL label content is sensitive — patient identifiers, lot numbers, PHI, internal SKUs. Existing online previewers (labelary.com and the like) require uploading your raw ZPL to a third-party service. This extension renders entirely on your machine: no fetch, no analytics, no label data ever leaves your laptop.
Same goes for printing — labels go directly from VS Code to your printer over your local network.
Architecture
src/
├─ extension.ts Activation, command registration, edit/save listeners
├─ parser.ts Pure-TS ZPL tokenizer/parser → intermediate command list
├─ previewPanel.ts Webview lifecycle, message routing, settings sync
├─ printer.ts Raw TCP send (Node net.Socket → port 9100)
├─ types.ts Shared TS types between parser, renderer, panel
└─ webview/renderer.ts Canvas renderer; delegates barcodes to bwip-js
syntaxes/zpl.tmLanguage.json TextMate grammar
snippets/zpl.json Common-pattern snippets
samples/sample.zpl Example label
Parser is strict-by-default but tolerates the ZDesigner preamble. Renderer composes commands onto a single <canvas> element sized to the label's physical dimensions × DPMM × zoom factor.
Known limitations
- Bitmap fonts are approximated with system fonts — character metrics won't match a Zebra printer pixel-for-pixel. Most layouts come out close; ultra-tight position-sensitive labels may need tweaking.
^GF raw binary streams (^GFB, ^GFC) are not supported. ASCII hex (^GFA), :Z64: (deflate+base64), and :B64: (base64) all decode correctly.
- Templates (
^DF / ^XF) and field number variables (^FN) are parsed but not substituted.
- Print-mode commands (
^MD, ^PR, ^PO, ^MN, etc.) are recognized but have no visual effect on the preview.
- Sending to printer assumes raw TCP / JetDirect — USB and Bluetooth printers are not supported (yet).
Building from source
npm install
npm run build # one-shot build
npm run watch # rebuild on save
To run in a sandboxed Extension Development Host: open the folder in VS Code → press F5.
Roadmap
^DF / ^XF template resolution with ^FN substitution.
- Raw binary
^GFB / ^GFC decoding.
- USB / Bluetooth printer transports.
- Ruler overlay + click-to-place coordinate readout in the preview.
License
MIT — see LICENSE.
Credits
| |