QRCode

A string a camera can read, drawn as one vector path, with an optional logo in the middle.

Open Source

Installation

QRCode ships with the library — install it once, then import:

import { QRCode } from "@delacour/react-native-ui/qr-code";

Or copy the source into your project, to own and edit it:

bunx delacour@latest add qr-code

QRCode needs nothing beyond react-native-svg, which the library already requires. The encoder is part of the component — no QR package is added to your project.

Usage

app/index.tsx
import { QRCode } from "@/components/ui/qr-code";
import { View } from "react-native";

export default function Example() {
  return (
    <View className="flex-1 items-center justify-center p-4">
      <QRCode value="https://ui.delacour.co.nz" accessibilityLabel="Open the Delacour docs" />
    </View>
  );
}
Anatomy
Anatomy

Module styles

square merges runs into rectangles. rounded rounds only the corners with no dark neighbour, so runs fuse into one shape. dots draws each module as a dot.

Module styles
<QRCode value={url} moduleStyle="square" />
<QRCode value={url} moduleStyle="rounded" />
<QRCode value={url} moduleStyle="dots" />

The three finder patterns in the corners stay a ring and a core in every style. A finder made of dots is one a decoder cannot lock onto.

Error correction

Each level survives more damage and pays for it in density. The default is M.

Error correction
Error correction
LevelRecoversBytes at version 1Version 10Version 40
L~7%172712 953
M~15%142132 331
Q~25%111511 663
H~30%71191 273
<QRCode value={url} errorCorrection="Q" />

Digits-only and upper-case values (0–9, A–Z, space and $%*+-./:) pack tighter than these byte counts; anything else is encoded as UTF-8.

A logo in the middle

QRCode.Logo puts a mark on a plate cleared out of the centre. A logo is damage the code has to correct, so its presence raises the level to H — a lower errorCorrection is overridden and warns in development. logoSize is the share of the side the plate may take, from 0.1 to 0.3.

With a logo
<QRCode value={url} moduleStyle="rounded" logoSize={0.24} accessibilityLabel="Open the menu">
  <QRCode.Logo>
    <Icon icon={IconStar} size={32} color="#000000" />
  </QRCode.Logo>
</QRCode>

To keep every block recoverable, the code may grow a version, then shrink the logo toward 0.1. If even that is too much, the logo is dropped and a development warning says so — the code always scans.

Colours

The tile is black on white in both themes, and does not follow the theme on purpose: a QR code is read by someone else's camera, and light modules on a dark tile fail a large share of scanners.

Colours
Colours
<QRCode value={url} color="#1e3a8a" backgroundColor="#fef3c7" />

color and backgroundColor take a literal or a theme token. A pair that is inverted, or under 3:1 contrast, warns in development. Never invert a code.

Using the encoder directly

encodeQr is the pure encoder the component sits on. It returns a matrix any renderer can draw — Skia, a printed label, a server.

import { encodeQr } from "@/components/ui/qr-code";

const result = encodeQr("https://ui.delacour.co.nz", { errorCorrection: "Q" });
if (result.ok) {
  const { size, modules } = result.matrix;
  const isDark = (row: number, col: number) => modules[row * size + col] === 1;
}

Inside a component, useQRCode(value, options) returns the same result, memoised. Encoding a version-40 payload takes tens of milliseconds on the JS thread, so keep value stable rather than building it inside a list row's render.

Errors

The component never throws. An empty value or one too long for any version calls onEncodeError and renders an empty tile labelled "QR code unavailable".

<QRCode
  value={payload}
  onEncodeError={(error) => {
    if (error.kind === "too-long") setMessage(`${error.bytes} bytes; the limit is ${error.capacity}.`);
  }}
/>

Accessibility

The tile is an image to assistive technology. Its label is your accessibilityLabel, or "QR code: " followed by the value cut at 60 characters. Say what the code is for — a URL means nothing read aloud — and a development warning reminds you when you have not.

When the value is printed beside the code, as with a Wi-Fi password, pass isDecorative so a screen reader reads it once rather than twice. The logo is always hidden from assistive technology.

Printing and size

size is the whole tile, quiet zone included: sm 128, md 192, lg 256 points, or any number. Each module is snapped to a whole number of device pixels, so abutting runs never show a hairline seam. Keep the quiet zone at its default of four modules — below two warns — and print a code no smaller than 2 × 2 cm.

A QR code does not animate: motion mid-scan breaks the scan. Fade it in with opacity if you must, never with a scale or a transform.

API Reference

Anatomy

PartWhat it is
QRCodeThe tile — encodes the value and draws it as one path
QRCode.LogoA centred mark on a tile-coloured plate. Raises the level to H

QRCode

Prop

Type

Prop

Type

QrEncodeOptions

Prop

Type

QrMatrix

Prop

Type

QrEncodeError

Prop

Type

On this page