QRCode

A QR code drawn on canvas or as SVG, with an icon in the middle, an error correction level and an expired state that offers a refresh.

Usage

When to show a QR code, what to put in it, and the props that decide whether a camera can read it.

When to use

A QR code moves the reader from this screen to another device: a ticket, a table menu, a desktop-to-phone login, a pairing screen.
  • The reader is already on the device. Show a link. A phone cannot scan the screen it is holding.
  • A camera is not guaranteed. Show a short code the reader can type next to the QR code, so the QR code is a shortcut and not the only way in.
  • The destination changes while it is on screen. A code that redraws mid-scan fails with no explanation. Use status to take it out of service first.

What goes in the value

value is the whole payload and the only required prop. When it is empty, nothing renders and a warning appears in development. Keep it short: every extra character adds modules, and inside a fixed size each module gets smaller.
  • Encode a short URL that redirects on your server, not a long URL with its own query string.
  • Encode the address of a thing, not the thing. Do not put a token or anything you would not want a stranger to photograph in a code.
  • value also takes a string[], encoded as separate segments, which can pack tighter when a payload mixes digits and letters.

Canvas or SVG

type decides what the code is drawn into, and defaults to canvas.
  • canvas downloads as a PNG. Call toDataURL() on the <canvas>. A center icon is loaded so it does not block that. It is drawn at the screen's resolution, so it can blur in print.
  • svg prints. It stays sharp at any size on paper or in a PDF.
  • A CSS variable in color only works with type="svg". The default canvas cannot read CSS variables and paints the code black. For a canvas, read the token first with theme.useToken().

Error level and the center icon

errorLevel trades capacity for damage tolerance: L recovers about 7% of the code, M about 15%, Q about 25% and H about 30%. A higher level means more modules in the same box, each one smaller. The default, M, suits a code read off a clean screen.
  • icon is an image URL, drawn in the center of the code with the modules under it cleared. Error correction has to rebuild them.
  • Raise errorLevel when you add an icon. iconSize defaults to 40, a quarter of the default size of 160, which is more than M recovers well. Use Q or H, or shrink the icon.
  • The only warning is for icon with errorLevel="L". A code with a large logo can still fail on many phones without any warning.
  • Test the real code on a real phone, from the distance your readers will stand at.

Size, color and the border

size is the width of the square in px and defaults to 160. What decides whether a camera can read it is how large each module is, so a longer value or a higher errorLevel shrinks the modules at the same size.
  • Treat 160 as the minimum for a code read across a desk, and raise size rather than lowering errorLevel when the payload grows. A poster or a screen across a room needs much more.
  • color defaults to the text color and bgColor to transparent. In dark mode that gives light modules on a dark background, which some scanners refuse. Set both colors wherever scanning matters.
  • Scanners need contrast: dark modules on a light background, well past 4.5:1. A tinted code has less margin, and a light code on white has none.
  • bordered is on by default and sets the border, the corner radius and the padding around the code. Turning it off removes all three, and that padding is the only quiet zone the code has. Only drop the border on a light surface that leaves space around the code.

Expiry, refresh and status

You set status yourself. Nothing changes it for you. Set expired when the code times out, and go through loading back to active in onRefresh. Every status except active covers the code with an overlay.
  • Expire a code that grants access. A login or payment code that stays live on an unattended screen is what this status is for.
  • expired shows a refresh button only with onRefresh. Without it, the overlay shows the text alone and the reader has no way out.
  • scanned is a confirmation. Say what happens next on the other device, since the reader is now looking at their phone.
  • statusRender replaces all three statuses. Your function draws the overlay for expired, loading and scanned, not only the one you want to change. Use the locale it receives instead of writing the text in English.