In warehouses, online stores, and asset tracking systems, labels need to be printed constantly. Manual entry leads to errors and wasted time. We implemented a barcode generator for a logistics client who needed to print 500 labels per shift, each with a unique SKU. The solution uses JsBarcode running in the browser with no server requests — users see the result instantly and can send to print. This cuts printing costs by 30% and saves up to 40% of staff time. For a warehouse with 50 employees, that translates to savings of up to 50,000 RUB per month. Contact us to implement a solution in one day. Our on-site barcode implementation accounts for all format and device specifics. Get a free consultation for your project.
Selecting the Right Barcode Format
Choosing a format depends on the industry and data length. The table below lists the main formats we integrate. We assist with data validation and input field configuration.
| Format | Application | Data Length |
|---|---|---|
| Code 128 | Warehouse, logistics | Any length |
| EAN-13 | Retail, food products | 13 digits |
| EAN-8 | Small packages | 8 digits |
| Code 39 | Manufacturing, medical | Letters + digits |
| UPC-A | North America, retail | 12 digits |
| ITF-14 | Case packaging, SSCC | 14 digits |
| QR Code | "Honest Sign" marking (Russia) | Any data |
For retail, use EAN-13 or UPC-A (North America). For warehouses, Code128 accommodates any characters. For "Honest Sign" marking, QR or DataMatrix. Learn more about the Code 128 standard. We'll help you decide on the format at project start.
Why Client-Side Generation?
Server-side generation loads the CPU and adds latency. Client-side means zero TTFB — the barcode renders in the browser in milliseconds. JsBarcode is 3 times lighter than bwip-js and 5 times faster for client-side generation. For React, we wrap it in hooks — no unnecessary re-renders.
| Characteristic | Client-side | Server-side |
|---|---|---|
| Display latency | Instant | Network-dependent |
| Server load | None | High |
| Bulk printing | Limited (browser) | Yes (any volume) |
JsBarcode Library and React Component
The JsBarcode library supports all popular formats and works with <canvas>, <svg>, and <img>.
npm install jsbarcode
npm install -D @types/jsbarcode
import JsBarcode from 'jsbarcode'
import { useEffect, useRef } from 'react'
interface BarcodeProps {
value: string
format?: string
width?: number
height?: number
displayValue?: boolean
lineColor?: string
background?: string
fontSize?: number
margin?: number
}
export function Barcode({
value,
format = 'CODE128',
width = 2,
height = 80,
displayValue = true,
lineColor = '#000000',
background = '#ffffff',
fontSize = 14,
margin = 10,
}: BarcodeProps) {
const svgRef = useRef<SVGSVGElement>(null)
useEffect(() => {
if (!svgRef.current || !value) return
try {
JsBarcode(svgRef.current, value, {
format,
width,
height,
displayValue,
lineColor,
background,
fontSize,
margin,
textMargin: 4,
fontOptions: 'bold',
font: 'monospace',
})
} catch (e) {
console.warn(`Invalid barcode value "${value}" for format ${format}:`, e)
}
}, [value, format, width, height, displayValue, lineColor, background, fontSize, margin])
return <svg ref={svgRef} />
}
Batch and Server-Side Generation
Printing labels on A4
To print multiple barcodes on one page, we use a LabelSheet component. CSS Grid arranges labels in 3 columns with 4mm gaps — 24 labels fit on A4 without trimming. Printing opens a new window with @page { size: A4; margin: 0 } styles.
Thermal printer settings details
For thermal printers (Zebra, TSC), it's important to set label size and margins. We use CSS media queries and specify exact dimensions in millimeters. Example: @page { size: 58mm 40mm; margin: 0; }.function LabelSheet({ items }: { items: { sku: string; name: string; price: number }[] }) {
const printRef = useRef<HTMLDivElement>(null)
function handlePrint() {
const content = printRef.current!
const win = window.open('', '_blank')!
win.document.write(`
<html>
<head>
<title>Labels</title>
<style>
body { margin: 0; }
.sheet { display: grid; grid-template-columns: repeat(3, 1fr); gap: 4mm; padding: 10mm; }
.label { border: 0.5pt solid #ccc; padding: 3mm; text-align: center; page-break-inside: avoid; }
.label-name { font-size: 9pt; margin-bottom: 2mm; overflow: hidden; white-space: nowrap; }
.label-price { font-size: 14pt; font-weight: bold; margin-top: 2mm; }
@media print { @page { size: A4; margin: 0; } }
</style>
</head>
<body>
<div class="sheet">${content.innerHTML}</div>
</body>
</html>
`)
win.document.close()
win.focus()
win.print()
win.close()
}
return (
<div>
<button onClick={handlePrint} className="mb-4 px-4 py-2 bg-blue-600 text-white rounded">
Print Labels
</button>
<div ref={printRef} className="grid grid-cols-3 gap-1">
{items.map((item) => (
<div key={item.sku} className="border p-2 text-center text-xs">
<div className="truncate text-xs">{item.name}</div>
<Barcode value={item.sku} format="CODE128" height={50} fontSize={10} margin={4} />
<div className="font-bold">{item.price.toLocaleString('en-US')} USD</div>
</div>
))}
</div>
</div>
)
}
Server-Side Generation (Node.js)
When barcodes need to be generated on the backend — for mobile apps or mass printing — we use canvas. Install jsbarcode and canvas, then implement the function:
import { createCanvas } from 'canvas'
import JsBarcode from 'jsbarcode'
export function generateBarcodeBuffer(value: string, format = 'CODE128'): Buffer {
const canvas = createCanvas(400, 150)
JsBarcode(canvas, value, {
format,
width: 2,
height: 80,
displayValue: true,
fontSize: 14,
margin: 10,
})
return canvas.toBuffer('image/png')
}
// In an API route:
const buffer = generateBarcodeBuffer(req.query.sku)
res.setHeader('Content-Type', 'image/png')
res.send(buffer)
We add caching (Cache-Control: max-age=86400) for frequently requested SKUs to reduce server load.
EAN-13 with Checksum
The checksum is mandatory for EAN-13. Without it, scanners won't read the code. Implementation:
function calculateEAN13Checksum(digits: string): string {
if (digits.length !== 12) throw new Error('EAN-13 requires exactly 12 digits')
let sum = 0
for (let i = 0; i < 12; i++) {
sum += parseInt(digits[i]) * (i % 2 === 0 ? 1 : 3)
}
const checkDigit = (10 - (sum % 10)) % 10
return digits + checkDigit
}
const ean13 = calculateEAN13Checksum('460000000001')
Scanner Compatibility Testing
Even a properly generated barcode may fail to scan if contrast or size is off. We test on three popular scanners: Honeywell Xenon 1900, Zebra DS2208, and built-in smartphone cameras. Optimal bar width is 2-3 modules, height at least 30 mm. For EAN-13, we automatically verify the checksum. If issues arise after deployment, we provide two weeks of support.
Process, Timelines, and Pricing
What's included
- Component development for React/Vue/Angular
- Integration into existing system
- Label printing setup (A4, thermal printers)
- API for server-side generation (REST, GraphQL)
- Documentation and staff training
- Two weeks of post-deployment support
Steps:
- Analysis: identify formats, size requirements, and load
- Design: component architecture, API, storage
- Implementation: write code, test with real data
- Testing: verify scanning on various devices
- Deployment and support: upload, set up monitoring
Timelines range from 1 to 3 days depending on complexity (single vs multiple formats, client-side vs server-side printing). Pricing is determined individually — contact us for an estimate. We guarantee labels will scan on the first try. 5+ years of development experience, over 50 projects in logistics and retail.
Printing savings for a typical warehouse with 10 employees exceed 20,000 RUB per month. For a consultation and preliminary estimate, contact us.







