Reference

Everything <zpl-editor> offers a host page. How to use the load/save API in context: Embed the editor.

Attributes and properties#

Attributes are strings; every attribute also has a property (camelCase). Getters return the live state, including changes the user made in the editor's own controls.

AttributePropertyTypeDefault
valuevaluestringblank 4 x 6 labelThe ZPL template. Setting a different value replaces the document, clears the undo history and makes it the saved state; setting the current value (or the one the last change reported) does nothing. Never fires change. For documents from your database prefer load().
sample-datasampleDataobject | array (attribute: JSON)noneSample record(s): preview with sample data, the Variables tab, Export merged, Test with API.
dpmmdpmm6 | 8 | 12 | 248Printhead density.
width, heightwidth, heightinches, 0.1-154, 6Label size. Set from outside, they do not rewrite ^PW/^LL (the size menu in the editor does).
uprightuprightbooleantrueIgnore ^PO I so the label reads the right way up. upright="false" turns it off.
zoomzoomfit | actual | numberfitNumber = CSS pixels per printer dot (1 = 100%; "150%" works too).
api-baseapiBaseURLthe install the SDK was loaded fromThe labelviewer install used by Test with API and the API tab, and whose license applies. Loaded from /sdk/... it is that install's origin; bundled from npm it is empty (those features are hidden) until you set it. '' returns to the default.
fonts-base-urlfontsBaseUrlURLfonts/ next to the scriptWhere the font files are (SDK › Fonts). Read on connect.
readonlyreadonlybooleanfalseView and inspect only: no toolbox, no undo, no editing. Sample data and zoom still work.
featuresfeaturestokensall onTurn parts of the UI off, see Features.
warn-unsavedwarnUnsavedbooleanfalseWhile the template is unsaved, the browser asks before the page is closed or reloaded (beforeunload). Removed when the element leaves the page.
autosave-keyautosaveKeystringnonelocalStorage key for a draft (template, sample data, view) that survives reloads. Without it nothing is stored. Read on connect. See Drafts.
—saveHandlerfunctionnoneProperty only. ({ value, sampleData, settings, fileName }) => Promise<void | { value }>, called on Save. See Save it.
—samplesarraythe built-in starter samplesProperty only. The New from sample… gallery: [{ id, title, retailer?, description, widthIn, heightIn, dpmm, zpl, data? }] (retailer is a hint shown as "Similar fields to: …", data goes to the Sample data tab). [] hides the action; undefined restores the built-in list, so ed.samples = [...ed.samples, mine] adds one. The built-in samples are not verified (Starter samples).
—dirty (read-only)booleanThe template differs from the saved state (set by load(), value, markSaved() or a successful saveHandler).
—ready (read-only)PromiseResolves after the fonts are loaded and the first render is done.

Slot title: content shown at the start of the toolbar, e.g. <h1 slot="title">Templates</h1>.

Features#

features is a space-separated list of no-<feature> tokens. They hide UI only; the methods keep working.

TokenHides
no-fileThe file actions: New, New from sample, Open, Save, Copy, Export, Test with API
no-samplesNew from sample
no-historyUndo and redo buttons
no-settingsDensity, size and upright controls
no-helpThe keyboard shortcuts button
no-toolboxThe left pane (add element, field list)
no-propertiesThe right pane (properties of the selection)
no-code, no-data, no-variables, no-api, no-warningsThe bottom tabs: ZPL code, Sample data, Variables, API, Warnings. Without any tab the bottom panel goes away.
<!-- A layout-only designer: no file menu, no code, no API -->
<zpl-editor features="no-file no-code no-api"></zpl-editor>

Methods#

Method
load({ zpl, sampleData?, dpmm?, width?, height?, fileName? })Replace the document in one step: template, sample data (object, array or JSON text; omitted = none), density, size in inches and the file name reported by save. Clears the undo history, makes zpl the saved state (dirty = false) and fires no change. Throws a TypeError for a non-string zpl, an unknown density or a size outside 0.1-15 in.
markSaved(value?)Make value (default: the current template) the saved state, after your code stored it. Needed only without a saveHandler.
getValue(), setValue(zpl)Same as the value property.
render()Render now; returns { labels, warnings }.
exportMerged(data?)The template merged in the browser with data (default: the sample data). Throws a MergeError with details.
undo(), redo()
focus()Focuses the canvas, so keyboard shortcuts work.

Events#

All are CustomEvents that bubble and cross the shadow root.

EventdetailWhen
change{ value }Every edit by the user (canvas, properties, code, undo/redo, New, New from sample, Open). Code typing is debounced (150 ms); a drag fires once, on release. Not for load(), value or a stored value returned by saveHandler.
save{ value, sampleData, settings: { dpmm, widthIn, heightIn }, fileName }Ctrl/Cmd+S or the Save button, always, before the saveHandler runs. sampleData is a copy (undefined when there is none).
dirty-change{ dirty }dirty flipped.
select{ field, ordinals }The selection changed. field = { ordinal, kind, command, start, end, box } of the first selected field (box in label dots, null when it draws nothing), or null.
render{ labels, warnings }After each render (not during a drag). labels is the number of labels.
sample-load{ id }The user picked a sample in New from sample… and it replaced the document (after change).
error{ source, message, status?, details? }source: fonts, render, api (Test with API failed; status), save (the saveHandler threw), license (the install's license does not cover the Editor: a notice replaces the designer, and exportMerged() throws).

Native events of the inner controls that are composed (input, keydown, focus...) also reach listeners on the element; native change and select events do not leave the shadow root.

Keyboard shortcuts#

They act only while the focus is inside the element (click the canvas, or call focus()). Press ? in the editor for this list.

KeysAction
Click / Shift+ClickSelect / add to selection (click again to pick the element below)
DragMove; on an empty label area: select by rectangle
Arrow keysNudge 1 dot (Shift: 10 dots)
Del / BackspaceDelete the selection
Ctrl/Cmd+DDuplicate
Ctrl/Cmd+C / X / VCopy / cut / paste fields
Ctrl/Cmd+ASelect every field of the label
] / [Bring to front / send to back
Ctrl/Cmd+Z, Ctrl/Cmd+Shift+ZUndo, redo
+ / - / 0 / 1Zoom in / out / fit / 100%
Ctrl/Cmd+WheelZoom at the pointer
Space+Drag, WheelPan
Ctrl/Cmd+SSave the template
EscClear the selection
?Show the shortcuts

Theming#

Set these custom properties on the element (or any ancestor); they inherit into the shadow root:

PropertyDefault
--lv-accent#1f6febPrimary buttons, selection, focus, grid
--lv-accent-hover#1858c4Primary button hover
--lv-bg#f3f4f6Editor background
--lv-panel#ffffffPanes
--lv-border#d9dce1Borders
--lv-text#1f2933Text
--lv-muted#616e7cSecondary text
--lv-ok, --lv-warn, --lv-error#1a7f37, #9a6700, #cf222eStatus colours
--lv-font, --lv-font-monosystem UI, system monospaceFonts of the UI (not the label)
--lv-toolbar-bg, --lv-toolbar-text, --lv-toolbar-muted#24292f, #fff, #c9d1d9Toolbar
--lv-radius4pxControl corner radius
zpl-editor { height: 720px; --lv-accent: #7b3fe4; --lv-toolbar-bg: #2d2640; }

Parts for anything else (zpl-editor::part(toolbar) { ... }):

Part
shellEverything
toolbarThe top bar
toolboxThe left pane
canvasRulers and label
statusThe status bar
panelThe bottom tabs
propertiesThe right pane

Layout and lifecycle#

  • The element is height: 640px by default and needs about 1000 px of width; below that it scrolls horizontally. Its layout tightens below 1440 px of element width (a container query, not the window). In a display: flex parent, give it a min-height.
  • Several editors on one page are independent: each has its own document, history, selection and shortcuts.
  • Removing the element from the page tears it down (listeners, observers, timers). Moving it within the page keeps its state. Adding a removed element back starts a fresh editor with the same value, sample data and saved state.
  • value = ... and load() start a new document, so they are not undoable; user edits are.
  • Test with API sends POST ${apiBase}/v1/merge with the template and the sample data, with credentials: 'omit' and no credentials of any kind. If a gateway in front of the install requires credentials, do not put them in browser code: set api-base to a route on your backend that forwards to labelviewer, or hide the feature with features="no-api".

Troubleshooting#

SymptomCause
The editor is 0 px highGive it a height; a parent with display: flex may shrink it (min-height).
Test with API is missingBundled from npm: set api-base. Also check features (no-api, no-file).
"This label component is not licensed for this installation"The install's license does not cover the Editor: see the install's Status page.
A red X across the labelThe install runs on a trial license. The X is drawn on screen only: the template, saves and exports are not changed.
Save does nothing visibleWithout a saveHandler the editor only fires save and stays unsaved until markSaved().
A draft replaced the template I set with valueDrafts win over value; use load() for documents from your database, or a per-template autosave-key.
Keyboard shortcuts do nothingThey act only while the focus is inside the editor: click the canvas first, or call focus().
React: onChange never firesUse onchange (lower case) with React 19, or addEventListener('change', ...).
React: saveHandler / sampleData ignoredReact 18, or the module was loaded after React rendered the element. Use a ref.

Problems loading the SDK, fonts, CORS, integrity or CSP: SDK › Troubleshooting.