Guide
Logos, colours and shapes
A logo, safely
createQrCode(el, { value: 'https://devix.pk', logo: { src: '/logo.svg' } });
| Option | Default | |
|---|---|---|
src |
— | A URL, a data: URI, or SVG markup starting with <svg. |
size |
0.22 |
Share of the code's width, capped at 0.3. |
padding |
1 |
Light modules around it. |
clear |
true |
Punch the modules out. Turn it off only if the logo is transparent. |
Why the size is capped
A QR code's error correction can rebuild a proportion of the data — nominally 7% at level L and 30% at level H. Those figures describe damage scattered across the code, such as a scratch or a smudge. A logo is a solid square in the middle, and the data is interleaved across blocks, so a square hole destroys whole codewords in a handful of blocks rather than a little of each. The usable share is therefore much smaller than the headline number.
We measured it: codes at every level were covered by a growing square and decoded
until they failed. The largest square that survived everywhere was about a
third of the nominal tolerance. That is what fitLogo() uses, and it is
deliberately the conservative end — telling someone their code will scan when it
will not is the failure that matters.
import { encode, fitLogo } from '@devix-labs/qr-code';
fitLogo(encode('https://devix.pk', { level: 'H' }), { src: 'x', size: 0.3 });
// { safe: false, maxSize: 0.21, fraction: 0.144, tolerance: 0.3, covered: 121 }
The widget does this for you: with fitLogoLevel on (the default) it raises the
level to H before giving up, and only warns if even H is not enough.
Practical advice
- Keep the logo square-ish. A wide logo wastes the budget on the modules above and below it.
- A logo with a solid background reads better than a transparent one, because the punched-out area is already light.
- Test the printed size. A code that scans at 400px on a screen may not at 2cm on a receipt, logo or no logo.
Colours
createQrCode(el, { value: 'x', dark: '#18181b', light: '#fafafa' });
createQrCode(el, { value: 'x', dark: '#3a86ff', light: 'none' }); // transparent
Contrast is what a scanner needs, and dark on light is what it expects. Inverting — light modules on a dark background — fails on many readers, so if you want a dark code on a dark page, keep the light modules light and give the code its own pale panel.
A safe rule: at least 40% contrast between the two, and never a light dark
colour. Pale grey on white is the most common reason a "designed" code does not
scan.
Module shapes
createQrCode(el, { value: 'x', shape: 'rounded' });
createQrCode(el, { value: 'x', shape: 'dot', finderShape: 'square' });
square is the shape every reader was built for. rounded is safe in practice.
dot leaves gaps between modules and is the riskiest — it looks best and scans
worst, so keep the error correction high and test it.
Shaping the modules but not the three corner finders — shape: 'dot' with
finderShape: 'square' — is the combination that stays most reliable, because
the finders are what a reader locates first.
Size and the quiet zone
createQrCode(el, { value: 'x' }); // fluid: fills its container
createQrCode(el, { value: 'x', size: 220 }); // fixed at 220px
createQrCode(el, { value: 'x', quiet: 2 }); // a narrower border
The four-module quiet zone is part of the specification, not decoration: readers
use it to find the edges. Narrowing it to save space is the second most common
reason a code does not scan. If you need the code tighter to its box, set
quiet: 0 and give the element its own light padding in CSS instead — the border
is then still there, it is just made of page rather than of SVG.