Skip to content
usefy

QRScanner

ComponentsQR scanning

QR code scanner for React — the platform's native BarcodeDetector where it exists, a hand-written ISO/IEC 18004 decoder where it doesn't. Camera and still image, Reed–Solomon error correction, zero dependencies.

Live demo

Install

$ npm install @usefy/qr-scanner

Quick start

QRScanner.tsx
import { QRScanner } from "@usefy/qr-scanner";

export function CheckIn() {
  return (
    <QRScanner
      onScan={(result) => {
        // A QR payload is untrusted input. Show it, validate it, then act.
        console.log(result.text, result.symbol?.version);
      }}
    />
  );
}

API reference

<QRScanner />

PropTypeDefaultDescription
onScan(result, all) => voidFired once per distinct value (see dedupeMs)
onFrame(results) => voidFired for every decode, repeats included
onError(error) => voidCamera and environment failures
source"camera" | "file""camera""file" never opens a camera
accentstring"#22d3ee"Viewfinder and highlight colour
pausedbooleanHold the loop; the camera stays open. Controllable — pair with defaultPaused / onPausedChange, or just use pause() / resume()
defaultPausedbooleanfalseInitial paused state when paused is not supplied
onPausedChange(paused) => voidFired whenever the paused state changes, from either side
facingMode"environment" | "user""environment"Preferred camera
deviceIdstringOpen one specific camera
scanRatenumber12Maximum decodes per second
dedupeMsnumber1500How long a repeated value is suppressed
stopOnHidebooleanfalseRelease the camera when the tab is hidden
showTorch / showSwitch / showFileFallbackbooleantrueControl visibility
decoderDecoderDecode elsewhere, e.g. a worker
controllerRefRef<QRScannerController>start / stop / pause / resume / scanFile / capture

Everything in Options is accepted too, and any other prop is forwarded to the wrapper element.

useQRScanner(options)

Returns { videoRef, state, result, results, error, start, stop, pause, resume, devices, activeDeviceId, selectDevice, switchCamera, isTorchSupported, torch, setTorch, scanFile, capture }.

state is one of idle · prompting · scanning · paused · denied · unsupported · error — enough to render every case without inspecting the error.

Decoding functions

FunctionDescription
decode(source, options?)Any image source → results, choosing an engine
decodeFile(blob, options?)The same, named for the call site
decodeFirst(source, options?)One result or null
decodeImageData(image, options?)Synchronous, DOM-free, internal engine only
isNativeSupported()Whether the platform can decode QR natively

Result

interface QRScanResult {
  text: string;                      // the decoded value
  bytes: Uint8Array;                 // raw payload, before any charset
  segments: QRScanSegment[];         // as the symbol carried them
  symbol?: QRSymbolInfo;             // internal engine only — see Engines
  corners: Quad;                     // TL, TR, BR, BL in source-image pixels
  center: Point;
  engine: "native" | "internal";
  timestamp: number;
}

interface QRSymbolInfo {
  version: number;                   // 1–40
  size: number;                      // 4v + 17
  level: "L" | "M" | "Q" | "H";
  mask: number;                      // 0–7
  mirrored: boolean;
  inverted: boolean;
  errorsCorrected: number;           // codewords Reed–Solomon repaired
  structuredAppend?: { index: number; total: number; parity: number };
  fnc1?: "gs1" | "aim";
}

Go deeper

This page is the quick reference. For every example, prop, and edge case, read the full README — or open Storybook to change props live.

More in components