Skip to content
| Marketplace
Sign in
Visual Studio Code>Programming Languages>ZPL Language & PreviewNew to Visual Studio Code? Get it now.
ZPL Language & Preview

ZPL Language & Preview

Tom Hohensee

|
66 installs
| (0) | Free
Offline ZPL language service and live preview — IntelliSense, hover docs, formatter, diagnostics, PDF export, and direct-to-printer.
Installation
Launch VS Code Quick Open (Ctrl+P), paste the following command, and press enter.
Copied to clipboard
More Info

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.

Live preview of a shipping label rendered side-by-side with the ZPL source — barcode, QR code, and address blocks all rendered offline.


Features

Editing

  • Syntax highlighting for .zpl, .prn, .lbl files (TextMate grammar).
  • IntelliSense / autocomplete — type ^ or ~ and get a categorized menu of every recognized command, with tab-stoppable argument placeholders.
  • Hover documentation — hover any command for signature, argument table, defaults, and an example. Hover a diagnostic squiggle for the explanation in the same tooltip.
  • Snippets for common patterns: label, field, box, code128, qr, fx.
  • Auto-formatter — Format Document (Shift+Alt+F) re-emits the source with configurable indent (none / label / field) and optional field compaction. Span-driven, idempotent, preserves original command text and the ZDesigner preamble verbatim.
  • Diagnostics — 18+ rule codes (ZPL001–ZPL901) covering structural errors (unclosed ^XA, stray ^XZ), field positioning, argument ranges, barcode payload shape (Code 39 / EAN / UPC / Code 11 / Plessey / POSTNET / Planet / MSI / etc.), ^GF sanity, template references. Reported as VS Code Problems with code links to ZPL: Explain Diagnostic for the full markdown explanation.
  • Click-to-source in the preview — click any element on the rendered label to jump to the corresponding line. Hover for a live highlight outline.

Preview & export

  • Live preview in a side panel — updates 150 ms after each keystroke.
  • Configurable printer DPMM (203 / 300 / 600 dpi), label dimensions, ink / background color, zoom, rotation — 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.

Templates and variables

  • ^DF / ^XF template resolution — when both the storing label (^DF<name>…^XZ) and the recalling label (^XF<name>…^XZ) are in the same document, the preview expands the template inline.
  • ^FN / ^FV slot substitution — value pairs like ^FN1^FDAcme Corp^FS are collected and substituted into the matching ^FN1 display field; the literal ^FD on the display field acts as a default.
  • Cross-document templates (^XF for a name not defined in the file) produce ZPL501 info diagnostics — the printer may have it stored, but the preview can't expand it.

Supported ZPL commands

211 of the ~223 commands in the ZPL II spec are recognized — full hover docs and completion for every one. Visualized in the preview:

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, ^FN, ^FV
Templates ^DF, ^XF
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
1D barcodes ^BC (Code 128), ^B3 (Code 39), ^BE (EAN-13), ^B8 (EAN-8), ^BU (UPC-A), ^B9 (UPC-E), ^BS (UPC/EAN ext.), ^BK (Codabar), ^BA (Code 93), ^B1 (Code 11), ^B2 (ITF), ^BJ (Std 2-of-5), ^BL (LOGMARS), ^BM (MSI Plessey), ^BP (Plessey), ^BR (GS1 DataBar), ^BT (TLC39), ^BV (Korean Postal), ^BZ (POSTNET), ^B5 (Planet)
2D barcodes ^BQ (QR), ^BX (Data Matrix), ^B7 (PDF417), ^BF (MicroPDF417), ^BD (MaxiCode), ^B0 / ^BN / ^BO (Aztec), ^B4 (Code 49), ^BB (Codablock), ^BI (ISBT-128)

Setup / media / mode / job-state / RFID / memory / comm commands (~150 in total — ^MM, ^MT, ^PR, ^PO, ^JS, ^MD, ^MN, ^MU, ^MW, ^PM, ^LR, ^LS, ^LT, ~SD, ~TA, all 17 ^R* RFID commands, all ^J* job-state commands, ~D* downloads, etc.) are parsed, validated, and documented but not visually rendered — they affect the physical printer, not the on-screen pixels.


Quick start

  1. Install ZPL Language & Preview from the marketplace.
  2. Open or create a file with extension .zpl, .prn, or .lbl (or set the language to "ZPL" via the status-bar mode picker).
  3. Click the preview icon in the editor title bar (or Cmd+Shift+P → ZPL: Open Preview to the Side).
  4. 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.
zpl.diagnostics.enabled true Master switch for the Problems-panel diagnostics.
zpl.diagnostics.previewLimitations false Also emit ZPL901 info notes for commands the printer executes but the preview doesn't visualize.
zpl.format.indent "label" Formatter indent style: none, label (inside ^XA/^XZ), or field (also inside ^FO/^FS).
zpl.format.compactFields false When formatting, keep each field on a single line instead of one command per line.

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 What it does
ZPL: Open Preview Open preview in the active column.
ZPL: Open Preview to the Side Open preview in a side column (most common).
ZPL: Explain Diagnostic Look up the long-form markdown explanation for a ZPLnnn code (uses the diagnostic at the cursor when present, otherwise prompts).
Format Document (built-in) Auto-format the active .zpl file using the in-tree formatter.

The two preview 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 → command IR with byte spans + line numbers
 ├─ commandSpecs.ts       Single source of truth: 211 CommandSpec entries with args, docs, examples
 ├─ validator.ts          Pure rule engine over the IR → typed Diagnostic[]
 ├─ formatter.ts          formatZpl() + DocumentFormattingEditProvider
 ├─ languageService.ts    DiagnosticCollection + debounced refresh on edit
 ├─ languageFeatures.ts   HoverProvider + CompletionItemProvider (consult commandSpecs)
 ├─ explain.ts            zpl.explainDiagnostic command (markdown lookup)
 ├─ 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, validator, panel
 └─ webview/renderer.ts   Canvas renderer; template expansion + slot substitution; bwip-js for barcodes
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. The renderer preprocesses commands once to lift ^DF…^XZ template blocks into a templates map and inline ^XF references, then composes the resulting flat command list onto a single <canvas> element sized to the label's physical dimensions × DPMM × zoom factor. The spec table in commandSpecs.ts is consumed by four different layers — parser recognition, validator argument checks (future), hover provider, and completion provider — adding a new command means a single new entry.


Known limitations

  • Bitmap fonts are approximated with the bundled Roboto Condensed font — 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 decoded. ASCII hex (^GFA, including RLE-compressed forms), :Z64:, and :B64: all render correctly.
  • Cross-document templates — ^XF<name> only expands in the preview when the matching ^DF<name>…^XZ is in the same file. Templates stored on the printer from a previous job aren't visible to the preview (it surfaces a ZPL501 info note in this case). The printer will still resolve them at print time.
  • Print-mode commands (^MD, ^PR, ^PO, ^MN, etc., plus the entire ~D* download family) are recognized, documented, and validated but have no visual effect on the preview — they control the physical printer, not the on-screen pixels. Enable zpl.diagnostics.previewLimitations if you want explicit info notes for each one.
  • Obscure commands not yet in the spec table — roughly a dozen rarely-used commands from the full ZPL II Programming Guide aren't yet recognized (some mobile-printer-only ^M* variants, a handful of legacy ^A@ extended-font selectors, etc.). They appear in the Problems panel as ZPL001 Unknown ZPL command. If you hit one in a real label, file an issue with the snippet — adding a spec entry is a one-line change.
  • 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

  • Raw binary ^GFB / ^GFC decoding.
  • USB / Bluetooth printer transports.
  • Ruler overlay + click-to-place coordinate readout in the preview.
  • Argument-level validation driven by the spec table (range checks, enum-validity per arg, type coercion warnings).
  • Quick fixes for common diagnostics (insert missing ^FS, swap to valid orientation, etc.).
  • Backfill the remaining ~12 long-tail commands as users surface them.

License

MIT — see LICENSE.

Credits

  • bwip-js — barcode rendering (31 symbologies).
  • pdf-lib — PDF export.
  • pako — :Z64: deflate decompression for ^GF.
  • Roboto Condensed (Apache 2.0) — bundled to approximate Zebra's condensed Triumvirate font.
  • Contact us
  • Jobs
  • Privacy
  • Manage cookies
  • Terms of use
  • Trademarks
© 2026 Microsoft