Spec & internals
QR code SVG path structure
A QR code becomes SVG as path data on a square grid. UseQR merges every dark module into one path element with a single fill, uses integer coordinates at eight pixels per module, and sets shape-rendering to crispEdges on square styles — which is why the output has no anti-aliasing seams between modules.
Two ways to draw the same matrix
Given a matrix of dark modules, an SVG generator has a choice:
One <rect> per module. Simple to emit, miserable to use: a version 5 code has around
700 dark modules, so the file carries ~700 elements, each independently styled, parsed and
rendered. Design tools grind on selection, and renderers anti-alias every rectangle's
edges separately.
One <path> for everything. Concatenate every module's outline into a single d
attribute and fill it once:
<path d="M32 32h8v8h-8z M48 32h8v8h-8z …" fill="#000000"/>
Each M…h…v…z run is one 8 × 8 module; thousands of modules become one element, one fill,
one node in every tool that opens the file. This is the structure UseQR emits — the whole
data region is a single path, with the three eyes drawn as separate paths (their ring
shape uses fill-rule="evenodd" to punch out the hole) so eye colour and shape can be
styled independently.
The seam problem, and the three-part fix
The classic defect in QR SVGs is a grid of hairlines between modules — visible on screen at some zoom levels, occasionally even in print. It is anti-aliasing: when adjacent shapes share an edge at a fractional coordinate, the renderer blends each shape's edge with the background separately, leaving a semi-transparent seam where they meet.
The fix is threefold, and all three parts appear in UseQR's output:
- Integer coordinates. Modules are placed at
(column + quietZone) × moduleSizewith a default module size of 8 px and quiet zone of 4 modules — every square-module coordinate is a whole number, so edges land exactly on the pixel grid. (Curved styles round path coordinates to three decimals — precise enough that adjacent curves meet without gaps.) - One merged path. Sub-paths of a single filled path are composited together, not blended edge-by-edge against the background, so shared edges cannot produce seams.
shape-rendering="crispEdges"on the root, applied only for the square module style, telling renderers to prefer hard edges over anti-aliasing. Rounded, dot and organic module styles omit it — they want smooth curves, and their geometry does not tile edge-to-edge anyway.
The parts around the path
A complete generated file is small and predictable: an optional <defs> block (gradients,
the logo's clipPath), a background <rect> (omitted entirely for
transparent codes), the merged data path,
three eye paths, then optional logo image and label text. The viewBox spans
(modules + 2 × quietZone) × moduleSize, so the quiet zone is
part of the document, not something the placing designer must remember to add.
One structural subtlety worth copying if you build your own: UseQR can emit an SVG Tiny
1.2 profile on request — no clipPath, no ARIA attributes, no shape-rendering —
because print RIPs, cutters and older Illustrator versions silently drop full-SVG features
they do not understand. Shipping markup a print shop's software ignores is how codes break
between proof and product; the print rationale
covers that hand-off.
How the same matrix becomes canvas pixels instead is on rendering a QR code from a matrix; and whatever the structure, /validate rasterising and decoding the result is the test that matters.
FAQ
Why does my QR code SVG have thin white lines between squares?
Anti-aliasing seams: adjacent shapes at fractional coordinates get their shared edges blended separately against the background. Fix it with integer module coordinates, merging modules into one path, and shape-rendering set to crispEdges.
Is one path better than many rects in a QR SVG?
Yes, for real use. One merged path means one element to style, faster parsing and rendering, no per-edge anti-aliasing between modules, and dramatically easier handling in design tools — a version 5 code is one node instead of roughly seven hundred.
What is shape-rendering crispEdges for?
It is an SVG hint telling renderers to favour sharp, unblended edges over anti-aliasing. On a square-module QR code it eliminates hairline seams; on rounded or dot styles it is omitted because those shapes should stay smooth.
Can I edit a QR code SVG in Illustrator or Figma?
You can recolour and scale it safely. Avoid reshaping or moving individual modules and never apply effects that shift geometry — and keep the quiet zone that the file's viewBox already includes. Verify the edited export still decodes before printing.
Try it — free, no signup
Related
- QR code anatomy — every region of the symbol — A labelled tour of a QR code: finder patterns, separators, timing, alignment, format and version information, the data region and the quiet zone.
- Rendering a QR code from a matrix — From boolean matrix to pixels — module size, quiet zone, device pixel ratio on canvas, and choosing PNG or SVG output. With pseudo-code.
- Vector vs raster QR codes — SVG scales infinitely; a raster QR must be 300+ DPI at final printed size — a 3 cm code needs at least 354 pixels. The print-shop arithmetic.
- How to make a QR code as an SVG — Choose SVG at download or add format=svg to the API URL. A vector QR code scales to any size with perfectly sharp modules and weighs a few kilobytes.
- Why you should print QR codes from SVG — Vector QR codes rasterise at the press's native resolution with exact module edges. The PNG-resample chain is how codes that looked sharp on screen die in print.