svelte-qr-label
v0.1.0
Published
Svelte 5 component for the QR Label Designer — drag-and-drop label designer with PDF, PNG, and ZPL export.
Maintainers
Keywords
Readme
svelte-qr-label
The official Svelte 5 component for the QR Layout Designer — drag-and-drop label design with PDF, PNG, and ZPL export.
Drop a fully featured label designer into your Svelte 5 app with a single component. Users can drag and drop elements, bind {{variables}} from your data schema, preview in real-time, and export to PDF, PNG, or ZPL for Zebra thermal printers.
Part of the QR Layout Tool monorepo — also available for React, Vue 3, and vanilla JS.
Live Demo
| Framework | Live Demo | Source Code | | :--- | :--- | :--- | | Svelte 5 | ▶ Open Demo | Source |

Features
- Drag & Drop Designer — visually place and resize text, QR, and barcode elements on a canvas
- Live Preview — see your label render with real sample data as you design
{{variable}}Data Binding — bind fields like{{name}},{{id}},{{department}}from your entity schema- Multi-Variable QR — join multiple fields into one QR scan with a configurable separator
- Rich Text Styling — font size, weight, alignment; color, font family, word wrap, and line height
- Label Size Presets — common shipping, badge, and tag sizes built in
- Snap-to-Grid — optional 1-unit grid snapping while dragging
- Alignment Toolbar — align selected elements to the label edges or center
- Undo / Redo — 20-step history (Ctrl+Z / Ctrl+Y)
- Keyboard Shortcuts — Delete, Arrow nudge, Shift+Arrow, Ctrl+D duplicate, Escape
- Dark Mode — built-in light and dark themes
- Flexible Units — design in mm, cm, in, or px
- JSON Output — saves a compact layout JSON you store in your backend
Installation
npm install svelte-qr-labelqrlayout-core and qrlayout-ui are included as direct dependencies — no extra installs needed.
Requirements: Svelte 5.0+ as a peer dependency.
Quick Start
<script lang="ts">
import QRLabelDesigner from 'svelte-qr-label';
import 'svelte-qr-label/style.css';
import type { StickerLayout, EntitySchema } from 'svelte-qr-label';
const schemas: Record<string, EntitySchema> = {
employee: {
label: 'Employee',
fields: [
{ name: 'fullName', label: 'Full Name' },
{ name: 'employeeId', label: 'Employee ID' },
{ name: 'department', label: 'Department' },
],
sampleData: {
fullName: 'Alice Johnson',
employeeId: 'EMP-001',
department: 'Engineering',
},
},
};
function handleSave(layout: StickerLayout) {
console.log('Saved:', layout);
}
</script>
<div style="width: 100vw; height: 100vh;">
<QRLabelDesigner
entitySchemas={schemas}
onsave={handleSave}
/>
</div>Loading an existing layout
<script lang="ts">
import { QRLabelDesigner } from 'svelte-qr-label';
import 'svelte-qr-label/style.css';
import type { StickerLayout } from 'svelte-qr-label';
let savedLayout = $state<StickerLayout | undefined>(
JSON.parse(localStorage.getItem('myLayout') ?? 'null') ?? undefined
);
function handleSave(layout: StickerLayout) {
localStorage.setItem('myLayout', JSON.stringify(layout));
savedLayout = layout;
}
</script>
<QRLabelDesigner
initialLayout={savedLayout}
entitySchemas={schemas}
onsave={handleSave}
/>Props
| Prop | Type | Required | Description |
| :--- | :--- | :---: | :--- |
| initialLayout | StickerLayout | ❌ | Layout to pre-load on mount. The designer re-creates itself when this changes. |
| entitySchemas | Record<string, EntitySchema> | ❌ | Field definitions for {{variable}} binding and live preview. The designer re-creates itself when this changes. |
| onsave | (layout: StickerLayout) => void | ❌ | Called when the user clicks "Save Layout". Uses Svelte 5's lowercase event convention. |
Svelte 5 note:
onsavefollows Svelte 5's lowercase prop convention for event handlers. It updates reactively without re-creating the designer canvas.
Save & Print Workflow
The designer produces a plain JSON layout object. Pass it with real data to StickerPrinter (re-exported from svelte-qr-label) to generate PDF, PNG, or ZPL output.
Export to PDF
Requires
jspdf:npm install jspdf
import { StickerPrinter } from 'svelte-qr-label';
const printer = new StickerPrinter();
const pdf = await printer.exportToPDF(layoutJSON, records);
pdf.save('badges.pdf');Export to ZPL (Zebra thermal printers)
import { StickerPrinter } from 'svelte-qr-label';
const printer = new StickerPrinter();
const zplPages = printer.exportToZPL(layoutJSON, records, { dpi: 203 });Export to PNG
import { StickerPrinter } from 'svelte-qr-label';
const printer = new StickerPrinter();
for (const record of records) {
const blob = await printer.exportToPNG(layoutJSON, record);
const a = Object.assign(document.createElement('a'), {
href: URL.createObjectURL(blob),
download: `${record.id}.png`,
});
a.click();
}TypeScript Types
interface StickerLayout {
id: string;
name: string;
width: number;
height: number;
unit: 'mm' | 'cm' | 'in' | 'px';
backgroundColor?: string;
targetEntity?: string;
elements: StickerElement[];
}
interface StickerElement {
id: string;
type: 'text' | 'qr' | 'barcode';
x: number;
y: number;
w: number;
h: number;
content: string;
qrSeparator?: string;
barcodeFormat?: 'CODE128' | 'EAN13' | 'UPCA' | 'CODE39' | 'ITF14';
style?: {
fontSize?: number;
fontWeight?: 'normal' | 'bold';
textAlign?: 'left' | 'center' | 'right';
verticalAlign?: 'top' | 'middle' | 'bottom';
fontFamily?: string;
color?: string;
backgroundColor?: string;
wordWrap?: boolean;
lineHeight?: number;
};
}
interface EntitySchema {
label: string;
fields: EntityField[];
sampleData: Record<string, string | number>;
}
interface EntityField {
name: string;
label: string;
}Use Cases
| Industry | Application | | :--- | :--- | | 🏭 Manufacturing & Warehousing | Packing slips, bin location tags, shipping labels | | 🎟️ Events & Conferences | Attendee badges with QR check-in codes | | 🏥 Healthcare | Patient wristbands, specimen labels, asset tracking | | 📦 Inventory & Retail | SKU labels, price tags, product QR codes | | 🏢 HR & Access Control | Employee ID cards, visitor passes | | 🔧 Maintenance & MRO | Machine asset tags with scannable maintenance links |
Related Packages
| Package | Description |
| :--- | :--- |
| qrlayout-core | Headless engine — render PNG, PDF, ZPL without the UI |
| qrlayout-ui | Framework-agnostic designer (vanilla TS) |
| react-qr-label | React wrapper |
| vue-qr-label | Vue 3 wrapper |
🤝 Contributors
License
MIT © Shashidhar Naik
Found this useful? Please ⭐ star the repository — it helps others discover the project!
