Zero-dependency barcode & QR code SVG generator. 40+ formats, styled QR codes, tree-shakeable. Pure TypeScript.
etiket
Zero-dependency barcode & QR code SVG generator.
40+ formats, styled QR codes, tree-shakeable. Pure TypeScript, works everywhere.
[!IMPORTANT]
undefinedVerified formats (18): QR Code, Data Matrix, PDF417, Aztec, Micro QR, rMQR, MaxiCode, MicroPDF417, Code 128, EAN-13, EAN-8, UPC-A, Code 39, Code 93, ITF, Codabar, GS1-128, Codablock F — verified with round-trip scan tests (zxing-wasm, rxing, gozxing) and/or 100% bit-match against Zint/bwip-js reference.undefinedExperimental formats: DotCode, Han Xin, JAB Code — no open-source decoder exists for these formats. Encoders produce structurally valid output (Han Xin 75% reference match, finders 100%). PRs welcome.
undefinedContributions welcome! If you find a scanning issue or want to improve an encoder, please open an issue or submit a PR. See Contributing below.
npm install etiket
import { barcode, qrcode } from "etiket";
const svg = barcode("Hello World");
const qr = qrcode("https://example.com", { dotType: "dots", ecLevel: "H" });
npx etiket qr "Hello World" -o qr.svg
npx etiket qr "Hello" --terminal
npx etiket qr "Hello" --size 300 --ec H --dot-type dots
npx etiket barcode "4006381333931" --type ean13 --show-text -o barcode.svg
npx etiket datamatrix "Hello" -o dm.svg
npx etiket pdf417 "Hello" -o pdf.svg
npx etiket aztec "Hello" -o aztec.svg
npx etiket wifi "MyNetwork" "secret123" -o wifi.svg
Import only what you need:
import { barcode } from "etiket/barcode"; // 1D barcodes only
import { qrcode } from "etiket/qr"; // QR codes only
import { datamatrix } from "etiket/datamatrix";
import { pdf417 } from "etiket/pdf417";
import { aztec } from "etiket/aztec";
| Format | Type | Description |
|---|---|---|
| undefinedCode 128undefined | code128 |
Auto charset (A/B/C) |
| undefinedCode 39undefined | code39 |
43-char set, optional check |
| undefinedCode 39 Extundefined | code39ext |
Full ASCII |
| undefinedCode 93undefined | code93 |
Higher density, 2 check digits |
| undefinedCode 93 Extundefined | code93ext |
Full ASCII |
| undefinedEAN-13undefined | ean13 |
Auto check digit |
| undefinedEAN-8undefined | ean8 |
Auto check digit |
| undefinedEAN-5undefined | ean5 |
Addon (book price) |
| undefinedEAN-2undefined | ean2 |
Addon (issue number) |
| undefinedUPC-Aundefined | upca |
12-digit, auto check digit |
| undefinedUPC-Eundefined | upce |
Compressed 8-digit |
| undefinedITFundefined | itf |
Interleaved 2 of 5 |
| undefinedITF-14undefined | itf14 |
14-digit with bearer bars |
| undefinedCodabarundefined | codabar |
Libraries, blood banks |
| undefinedMSI Plesseyundefined | msi |
Mod10/11/1010/1110 |
| undefinedPharmacodeundefined | pharmacode |
Pharmaceutical |
| undefinedCode 11undefined | code11 |
Telecommunications |
| undefinedGS1-128undefined | gs1-128 |
AI parsing, FNC1, 100+ AIs |
| undefinedGS1 DataBarundefined | gs1-databar |
Omnidirectional, 14-digit GTIN |
| undefinedGS1 DataBar Limitedundefined | gs1-databar-limited |
GTIN starting with 0/1 |
| undefinedGS1 DataBar Expandedundefined | gs1-databar-expanded |
Variable-length AI data |
| undefinedIdentcodeundefined | identcode |
Deutsche Post / DHL |
| undefinedLeitcodeundefined | leitcode |
Deutsche Post routing |
| undefinedPOSTNETundefined | postnet |
USPS legacy postal |
| undefinedPLANETundefined | planet |
USPS confirmation tracking |
| undefinedPlesseyundefined | plessey |
UK library systems |
| Format | Function | Description |
|---|---|---|
| undefinedQR Codeundefined | qrcode() |
Versions 1-40, all EC levels, all modes |
| undefinedMicro QRundefined | encodeMicroQR() |
M1-M4 (11x11 to 17x17) |
| undefinedData Matrixundefined | datamatrix() |
ECC 200, ASCII/C40/Text auto encoding |
| undefinedGS1 DataMatrixundefined | gs1datamatrix() |
FNC1 + AI parsing |
| undefinedPDF417undefined | pdf417() |
Text/Byte/Numeric, 9 EC levels, ISO-8859-15 |
| undefinedMicroPDF417undefined | encodeMicroPDF417() |
Compact PDF417 for small items |
| undefinedAztecundefined | aztec() |
Compact + full-range, no quiet zone |
| undefinedMaxiCodeundefined | encodeMaxiCode() |
33×30 hexagonal, UPS shipping labels |
| undefinedrMQRundefined | encodeRMQR() |
Rectangular Micro QR (R7x43 to R17x139) |
| undefinedCodablock Fundefined | encodeCodablockF() |
Stacked Code 128 |
| undefinedCode 16Kundefined | encodeCode16K() |
Stacked barcode, 2-16 rows |
| undefinedDotCodeundefined | encodeDotCode() |
Checkerboard dots, high-speed printing |
| undefinedHan Xinundefined | encodeHanXin() |
Chinese market, 84 versions, 4 finders |
| undefinedJAB Codeundefined | encodeJABCode() |
Polychrome (4/8 color), ISO/IEC 23634 |
| Format | Function | Description |
|---|---|---|
| undefinedRM4SCCundefined | encodeRM4SCC() |
Royal Mail (UK) |
| undefinedKIXundefined | encodeKIX() |
PostNL (Netherlands) |
| undefinedAustralia Postundefined | encodeAustraliaPost() |
Australia Post |
| undefinedJapan Postundefined | encodeJapanPost() |
Japan Post (Kasutama) |
| undefinedUSPS IMbundefined | encodeIMb() |
Intelligent Mail (US) |
import { barcode } from "etiket";
barcode("Hello World"); // Code 128 (default)
barcode("4006381333931", { type: "ean13", showText: true });
barcode("00012345678905", { type: "itf14", bearerBars: true });
barcode("(01)12345678901234(17)260101", { type: "gs1-128" });
barcode("HELLO", { type: "code39", code39CheckDigit: true });
| Option | Type | Default | Description |
|---|---|---|---|
type |
BarcodeType |
'code128' |
Barcode format |
height |
number |
80 |
Bar height in pixels |
barWidth |
number |
2 |
Width multiplier per module |
color |
string |
'#000' |
Bar color |
background |
string |
'#fff' |
Background color |
showText |
boolean |
false |
Show human-readable text |
textPosition |
'bottom' | 'top' |
'bottom' |
Text position |
fontSize |
number |
14 |
Text font size |
fontFamily |
string |
'monospace' |
Text font family |
margin |
number |
10 |
Margin around barcode |
marginTop |
number |
margin |
Top margin |
marginBottom |
number |
margin |
Bottom margin |
marginLeft |
number |
margin |
Left margin |
marginRight |
number |
margin |
Right margin |
textAlign |
'center' | 'left' | 'right' |
'center' |
Text alignment |
rotation |
0 | 90 | 180 | 270 |
0 |
Barcode rotation |
bearerBars |
boolean |
false |
Bearer bars (ITF-14) |
barGap |
number |
0 |
Extra spacing between bars |
unit |
'px' | 'mm' | 'in' | 'cm' |
'px' |
Measurement unit |
ariaLabel |
string |
— | SVG aria-label attribute |
title |
string |
— | SVG <title> element |
desc |
string |
— | SVG <desc> element |
import { qrcode } from "etiket";
qrcode("https://example.com");
qrcode("Hello", { size: 300, ecLevel: "H", dotType: "rounded" });
// With gradient
qrcode("Test", {
color: {
type: "linear",
rotation: 45,
stops: [
{ offset: 0, color: "#ff0000" },
{ offset: 1, color: "#0000ff" },
],
},
});
// With corner styling
qrcode("Test", {
dotType: "dots",
corners: {
topLeft: { outerShape: "rounded", innerShape: "dots", outerColor: "#ff0000" },
topRight: { outerShape: "extra-rounded" },
bottomLeft: { outerShape: "dots" },
},
});
| Option | Type | Default | Description |
|---|---|---|---|
size |
number |
200 |
SVG size in pixels |
ecLevel |
'L' | 'M' | 'Q' | 'H' |
'M' |
Error correction level |
version |
number |
auto | QR version (1-40) |
mode |
'numeric' | 'alphanumeric' | 'byte' | 'auto' |
'auto' |
Encoding mode |
mask |
0-7 |
auto | Mask pattern |
color |
string | GradientOptions |
'#000' |
Module color |
background |
string | GradientOptions |
'#fff' |
Background color |
margin |
number |
4 |
Quiet zone in modules |
dotType |
DotType |
'square' |
Module shape |
dotSize |
number |
1 |
Module size (0.1-1) |
shape |
'square' | 'circle' |
'square' |
Overall QR shape |
corners |
object |
— | Finder pattern styling |
logo |
LogoOptions |
— | Center logo embedding |
xmlDeclaration |
boolean |
false |
Add XML declaration |
unit |
'px' | 'mm' | 'in' | 'cm' |
'px' |
Measurement unit |
ariaLabel |
string |
— | SVG aria-label |
title |
string |
— | SVG <title> element |
desc |
string |
— | SVG <desc> element |
undefinedDot types: square, rounded, dots, diamond, classy, classy-rounded, extra-rounded, vertical-line, horizontal-line, small-square, tiny-square
import { datamatrix, pdf417, aztec } from "etiket";
datamatrix("Hello World");
pdf417("Hello World", { ecLevel: 4, columns: 5 });
aztec("Hello World", { ecPercent: 33 });
import {
barcode,
qrcode,
barcodeDataURI,
qrcodeDataURI,
barcodeBase64,
qrcodeBase64,
qrcodeTerminal,
} from "etiket";
const svg = qrcode("Hello"); // SVG string
const uri = qrcodeDataURI("Hello"); // data:image/svg+xml,...
const b64 = qrcodeBase64("Hello"); // data:image/svg+xml;base64,...
const term = qrcodeTerminal("Hello"); // Terminal (UTF-8 blocks)
import { wifi, email, sms, geo, url, phone, vcard, mecard, event } from "etiket";
wifi("MyNetwork", "password123"); // WiFi QR
email("test@example.com"); // mailto: QR
sms("+1234567890", "Hello!"); // SMS QR
geo(37.7749, -122.4194); // Location QR
url("https://example.com"); // URL QR
phone("+1234567890"); // tel: QR
// vCard QR
vcard({
firstName: "John",
lastName: "Doe",
phone: "+1234567890",
email: "john@example.com",
org: "Acme Inc",
});
// MeCard QR (simpler, used by Android)
mecard({ name: "John Doe", phone: "+1234567890", email: "john@example.com" });
// Calendar event QR
event({
title: "Meeting",
start: "2026-04-01T10:00:00",
end: "2026-04-01T11:00:00",
location: "Office",
});
import { validateBarcode, isValidInput, validateQRInput } from "etiket";
validateBarcode("4006381333931", "ean13"); // { valid: true }
validateBarcode("ABC", "ean13"); // { valid: false, error: '...' }
isValidInput("HELLO", "code39"); // true
Generate QR-bill payment codes (mandatory in Switzerland since 2022):
import { swissQR } from "etiket";
swissQR({
iban: "CH4431999123000889012",
creditor: { name: "Max Muster", postalCode: "8000", city: "Zürich", country: "CH" },
amount: 1949.75,
currency: "CHF",
reference: "210000000003139471430009017",
referenceType: "QRR",
});
Access encoding functions directly for custom rendering:
import {
encodeCode128,
encodeEAN13,
encodeQR,
encodeDataMatrix,
encodePDF417,
encodeAztec,
renderBarcodeSVG,
renderQRCodeSVG,
renderMatrixSVG,
} from "etiket";
const bars = encodeCode128("data"); // number[] (bar/space widths)
const matrix = encodeQR("data"); // boolean[][] (QR matrix)
const dm = encodeDataMatrix("data"); // boolean[][] (Data Matrix)
const svg = renderBarcodeSVG(bars, { height: 100 });
const qrSvg = renderQRCodeSVG(matrix, { size: 400, dotType: "dots" });
import {
swissQR,
gs1datamatrix,
gs1DigitalLink,
encodeHIBCPrimary,
encodeHIBCSecondary,
} from "etiket";
// Swiss QR-bill (mandatory in Switzerland since 2022)
swissQR({
iban: "CH4431999123000889012",
creditor: { name: "Max Muster", postalCode: "8000", city: "Zürich", country: "CH" },
amount: 1949.75,
currency: "CHF",
});
// GS1 DataMatrix (healthcare, supply chain)
gs1datamatrix("(01)12345678901234(17)260101(10)BATCH01");
// GS1 Digital Link (2027 retail migration)
gs1DigitalLink({ gtin: "09520123456788", batch: "ABC123", serial: "12345" });
// HIBC (medical device labeling, FDA UDI)
const hibc = encodeHIBCPrimary("A123", "PROD456");
barcode(hibc, { type: "code128" }); // Encode in any symbology
// ISBT 128 (blood bank labeling, ISO 7064 Mod 37-2 check character)
const din = encodeISBT128DIN("US", "12345", "26", "000001");
barcode(din, { type: "code128" });
// MaxiCode (UPS shipping labels)
const mc = encodeMaxiCode("Test shipment", {
mode: 2,
postalCode: "12345",
countryCode: 840,
serviceClass: 1,
});
All SVG renderers support accessibility attributes out of the box:
barcode("123456789", {
type: "ean13",
ariaLabel: "EAN-13 barcode for product 123456789",
title: "Product Barcode",
desc: "EAN-13 barcode encoding the GTIN 123456789",
});
qrcode("https://example.com", {
ariaLabel: "QR code linking to example.com",
title: "Website QR Code",
});
// CSS currentColor support for theme-aware barcodes
barcode("HELLO", { color: "currentColor", background: "transparent" });
npx etiket)optimizeSVG() for compact inlineariaLabel, role, title, desc)px, mm, in, cm, pt) for print use casescurrentColor support for theme-aware barcodes| Feature | etiket | uqr | bwip-js | JsBarcode | qr-code-styling |
|---|---|---|---|---|---|
| Zero dependencies | :white_check_mark: | :white_check_mark: | :x: (1.5MB+) | :x: (xmldom) | :x: (qrcode) |
| TypeScript-first | :white_check_mark: | :white_check_mark: | :x: | :x: | Partial |
| Tree-shakeable | :white_check_mark: | :x: | :x: | :x: | :x: |
| 1D barcodes (22 types) | :white_check_mark: | :x: | :white_check_mark: (100+) | :white_check_mark: (13) | :x: |
| QR Code (v1-40, all EC) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: |
| Data Matrix | :white_check_mark: | :x: | :white_check_mark: | :x: | :x: |
| PDF417 | :white_check_mark: | :x: | :white_check_mark: | :x: | :x: |
| Aztec Code | :white_check_mark: | :x: | :white_check_mark: | :x: | :x: |
| QR dot styling (12 types) | :white_check_mark: | :x: | :x: | :x: | :white_check_mark: |
| QR gradients | :white_check_mark: | :x: | :x: | :x: | :white_check_mark: |
| QR corner styling | :white_check_mark: | :x: | :x: | :x: | :white_check_mark: |
| QR logo embedding | :white_check_mark: | :x: | :x: | :x: | :white_check_mark: |
| CLI tool | :white_check_mark: | :x: | :white_check_mark: | :x: | :x: |
| Terminal output | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: |
| Convenience helpers (WiFi, vCard…) | :white_check_mark: | :x: | :x: | :x: | :x: |
| Input validation | :white_check_mark: | :x: | :x: | :x: | :x: |
| SVG output | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| PNG/Canvas output | :x: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| Pure ESM | :white_check_mark: | :white_check_mark: | :x: (CJS) | :x: (CJS) | :x: (CJS) |
| Bundle size (gzip) | ~24KB | ~12KB | ~160KB | ~15KB | ~30KB+deps |
undefinedetiket is the only library that combines 1D barcodes + 2D codes + styled QR codes + zero dependencies + tree-shaking in a single package.
Built from scratch, inspired by these excellent libraries:
Standards: ISO/IEC 15417 (Code 128), ISO/IEC 15420 (EAN/UPC), ISO/IEC 18004 (QR), ISO/IEC 16022 (Data Matrix), ISO/IEC 15438 (PDF417), ISO/IEC 24778 (Aztec), ISO/IEC 24724 (GS1 DataBar), ISO/IEC 16023 (MaxiCode), ISO/IEC 23941 (rMQR), ISO/IEC 20830 (Han Xin), ISO/IEC 23634 (JAB Code), AIM ISS DotCode 4.0 (DotCode), USPS-B-3200 (IMb).
Contributions are welcome! Here are some areas where help is especially appreciated:
undefinedEncoder improvements needed:undefined
undefinedOther contributions:undefined
pnpm install # Install dependencies
pnpm dev # Run tests in watch mode
pnpm test # Lint + typecheck + test
pnpm build # Build for production
Published under the MIT license.
We use cookies
We use cookies to analyze traffic and improve your experience. You can accept or reject analytics cookies.