vue-qr-label
v0.1.1
Published
Vue 3 component for the QR Label Designer — drag-and-drop label designer with PDF, PNG, and ZPL export.
Maintainers
Keywords
Readme
vue-qr-label
The official Vue 3 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 Vue 3 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, Svelte 5, and vanilla JS.
Live Demo

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 vue-qr-labelqrlayout-core and qrlayout-ui are included as direct dependencies — no extra installs needed.
Quick Start
<script setup lang="ts">
import { QRLabelDesigner } from 'vue-qr-label';
import 'vue-qr-label/style.css';
import type { StickerLayout, EntitySchema } from 'vue-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>
<template>
<div style="width: 100vw; height: 100vh;">
<QRLabelDesigner
:entity-schemas="schemas"
@save="handleSave"
/>
</div>
</template>Loading an existing layout
<script setup lang="ts">
import { ref } from 'vue';
import { QRLabelDesigner } from 'vue-qr-label';
import 'vue-qr-label/style.css';
import type { StickerLayout } from 'vue-qr-label';
const savedLayout = ref<StickerLayout>(
JSON.parse(localStorage.getItem('myLayout') ?? 'null')
);
function handleSave(layout: StickerLayout) {
localStorage.setItem('myLayout', JSON.stringify(layout));
savedLayout.value = layout;
}
</script>
<template>
<QRLabelDesigner
:initial-layout="savedLayout"
:entity-schemas="schemas"
@save="handleSave"
/>
</template>Props & Events
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. |
Events
| Event | Payload | Description |
| :--- | :--- | :--- |
| save | StickerLayout | Emitted when the user clicks "Save Layout" |
Save & Print Workflow
The designer produces a plain JSON layout object. Pass it with real data to StickerPrinter (re-exported from vue-qr-label) to generate PDF, PNG, or ZPL output.
Export to PDF
Requires
jspdf:npm install jspdf
import { StickerPrinter } from 'vue-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 'vue-qr-label';
const printer = new StickerPrinter();
const zplPages = printer.exportToZPL(layoutJSON, records, { dpi: 203 });Export to PNG
import { StickerPrinter } from 'vue-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 |
| svelte-qr-label | Svelte 5 wrapper |
🤝 Contributors
License
MIT © Shashidhar Naik
Found this useful? Please ⭐ star the repository — it helps others discover the project!
