QRScanner
ComponentsQR scanningQR 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-scannerQuick start
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 />
| Prop | Type | Default | Description |
|---|---|---|---|
onScan | (result, all) => void | — | Fired once per distinct value (see dedupeMs) |
onFrame | (results) => void | — | Fired for every decode, repeats included |
onError | (error) => void | — | Camera and environment failures |
source | "camera" | "file" | "camera" | "file" never opens a camera |
accent | string | "#22d3ee" | Viewfinder and highlight colour |
paused | boolean | — | Hold the loop; the camera stays open. Controllable — pair with defaultPaused / onPausedChange, or just use pause() / resume() |
defaultPaused | boolean | false | Initial paused state when paused is not supplied |
onPausedChange | (paused) => void | — | Fired whenever the paused state changes, from either side |
facingMode | "environment" | "user" | "environment" | Preferred camera |
deviceId | string | — | Open one specific camera |
scanRate | number | 12 | Maximum decodes per second |
dedupeMs | number | 1500 | How long a repeated value is suppressed |
stopOnHide | boolean | false | Release the camera when the tab is hidden |
showTorch / showSwitch / showFileFallback | boolean | true | Control visibility |
decoder | Decoder | — | Decode elsewhere, e.g. a worker |
controllerRef | Ref<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
| Function | Description |
|---|---|
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.