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.