react-qr-code, react-qr-reader, and react-qr-scanner address two distinct sides of the QR code workflow: generation and scanning. react-qr-code is a dedicated library for rendering QR codes as SVG or Canvas elements directly within React components, making it ideal for displaying dynamic data like tickets or Wi-Fi credentials. In contrast, react-qr-reader and react-qr-scanner focus on capturing and decoding QR codes from camera feeds or image files. While react-qr-reader was an early standard for this functionality, it is now deprecated and unmaintained. react-qr-scanner serves as its modern, actively maintained successor, offering improved browser compatibility, better handling of media streams, and continued support for contemporary React versions.
When building applications that interact with QR codes, developers usually face one of two distinct challenges: generating a code for users to scan, or scanning a code presented by the user. The ecosystem offers three notable packages to handle these tasks, but they serve very different purposes and carry different levels of risk. Let's break down how react-qr-code, react-qr-reader, and react-qr-scanner work under the hood and when to use them.
react-qr-code is purely a rendering engine. It takes a string value and converts it into a visual QR code using SVG or Canvas. It does not access your camera, nor does it decode images. Its main strength lies in its simplicity and scalability β since it often defaults to SVG, the output looks crisp on any device, from mobile phones to large displays.
This package is ideal for generating dynamic content, such as one-time login tokens, Wi-Fi connection strings, or payment links. You simply pass the data as a prop, and the component handles the complex math of encoding that data into the black-and-white pattern.
// react-qr-code: Generating a Wi-Fi login QR
import QRCode from 'react-qr-code';
function WifiTicket() {
const wifiString = 'WIFI:S:MyNetwork;T:WPA;P:secret123;;';
return (
<div style={{ height: 'auto', margin: '0 auto', maxWidth: 256, width: '100%' }}>
<QRCode
size={256}
style={{ height: 'auto', maxWidth: '100%', width: '100%' }}
value={wifiString}
viewBox={`0 0 256 256`}
/>
</div>
);
}
For scanning, the landscape has shifted. Historically, react-qr-reader was the go-to solution. It wrapped browser media APIs to access the webcam and used a JavaScript decoding library to interpret the video stream. However, the maintenance of this package has stopped. It is now marked as deprecated, meaning it will not receive updates for security vulnerabilities or compatibility with new browser standards.
react-qr-scanner emerged as the community-driven successor to fix these issues. It retains a similar API surface to make migration easier but updates the underlying dependencies to handle modern browser permissions, better error handling for camera access, and improved performance on mobile devices. If you are starting a new project today, react-qr-scanner is the only safe choice for scanning functionality.
// react-qr-scanner: Modern scanning implementation
import { Scanner } from '@yudiel/react-qr-scanner';
function ModernScanner({ onResult }) {
return (
<Scanner
onScan={(result) => onResult(result?.[0]?.text)}
onError={(error) => console.log(error?.message)}
scanDelay={500}
/>
);
}
// react-qr-reader: Deprecated legacy implementation (DO NOT USE)
import QrReader from 'react-qr-reader';
function LegacyScanner({ onResult }) {
return (
<QrReader
delay={300}
onError={(error) => console.log(error)}
onResult={(result) => {
if (result) {
onResult(result.getText());
}
}}
style={{ width: '100%' }}
/>
);
}
Accessing the camera is a sensitive operation that requires explicit user permission. Both scanning libraries handle this, but their approaches to error reporting differ due to their age.
react-qr-scanner provides a dedicated onError prop that captures modern DOMExceptions, such as when a user denies permission or when no camera device is found. It allows you to gracefully degrade the UI, perhaps showing a manual text input field instead of crashing the app.
react-qr-reader also had an onError handler, but because it is no longer updated, it may not correctly interpret newer browser error codes or handle edge cases on iOS Safari, which has strict autoplay and camera policies. Relying on it can lead to silent failures where the camera simply never starts.
// react-qr-scanner: Robust error handling
<Scanner
onScan={(result) => console.log(result)}
onError={(error) => {
if (error?.message?.includes('permission')) {
alert('Please allow camera access to scan codes.');
}
}}
/>
// react-qr-reader: Legacy error handling (Unreliable on new browsers)
<QrReader
onResult={(result) => console.log(result)}
onError={(error) => {
// May not catch specific modern permission errors reliably
console.error('Camera error:', error);
}}
/>
Sometimes users cannot point their camera at a code β maybe they have a screenshot saved on their device. Both libraries historically supported scanning from file inputs, but the implementation in the maintained library is more robust.
react-qr-scanner supports scanning from image files directly through its configuration or by passing a file reference, ensuring the decoding logic works with modern image blob formats. This is crucial for web apps where users might upload a ticket screenshot.
react-qr-reader required specific props to handle image files, and its underlying decoding engine is outdated. It may struggle with newer image compression formats or high-resolution screenshots that modern phones produce.
// react-qr-scanner: Scanning from an image file
// Note: Implementation often involves passing the file to the scanner component
// or using a dedicated image scanning mode if supported by the version.
<Scanner
onScan={(result) => console.log('Scanned from image:', result)}
// Specific props for image scanning may vary by version,
// but the library actively maintains these features.
/>
// react-qr-reader: Legacy image scanning (Fragile)
<QrReader
// Legacy approach often required separate logic or specific constraints
// to handle file inputs reliably.
constraints={{ video: false }} // Hypothetical legacy constraint
/>
If your codebase currently uses react-qr-reader, you should treat it as technical debt. The migration to react-qr-scanner is generally straightforward because the core concept remains the same: a component that renders a video element and calls a callback with the decoded text.
The main changes involve updating the import paths, adjusting the callback signatures (as react-qr-scanner often returns an array of results or a specific result object rather than a raw string directly in some versions), and ensuring your build pipeline supports the newer dependencies. Making this switch ensures your application remains secure and functional as browsers evolve.
// Migration Example: Switching imports and result handling
// OLD (react-qr-reader)
// import QrReader from 'react-qr-reader';
// onResult={(result) => result && setData(result.getText())}
// NEW (react-qr-scanner)
import { Scanner } from '@yudiel/react-qr-scanner';
// onScan={(result) => result && setData(result[0]?.text)}
| Feature | react-qr-code | react-qr-reader | react-qr-scanner |
|---|---|---|---|
| Primary Function | Generate / Display QR Codes | Scan / Decode QR Codes | Scan / Decode QR Codes |
| Maintenance Status | β Active | β Deprecated | β Active |
| Input Source | Text String | Camera / Image File | Camera / Image File |
| Output Format | SVG / Canvas | Decoded Text String | Decoded Text / Object |
| Browser Support | High (SVG based) | Low (Legacy APIs) | High (Modern APIs) |
| Recommended For | All new generation tasks | None (Legacy only) | All new scanning tasks |
Your choice depends entirely on whether you are creating a code or reading one.
If you need to display a QR code, react-qr-code is the industry standard. It is lightweight, dependency-free (regarding camera APIs), and produces scalable vector graphics that look professional on any device.
If you need to scan a QR code, you must use react-qr-scanner. It provides the same functionality as the old react-qr-reader but with the critical benefit of active maintenance. Using the deprecated react-qr-reader in a new project is a significant risk, as it may break with future browser updates or React versions. Stick to the maintained tools to ensure your application remains robust and secure.
Choose react-qr-code when your primary requirement is to generate and display QR codes within your application interface. It is the standard choice for rendering static or dynamic data (like URLs or payment info) as high-quality SVGs that scale perfectly on any screen resolution. Use this if you do not need camera access or decoding capabilities, as it focuses solely on the visual representation of the code.
Do NOT choose react-qr-reader for any new projects. This package is officially deprecated and no longer receives security updates or bug fixes. It relies on older browser APIs that may break in modern environments and lacks support for recent React versions. Existing projects using this library should plan an immediate migration to react-qr-scanner to ensure stability and security.
Choose react-qr-scanner when you need to implement QR code decoding from a live camera feed or uploaded images in a modern React application. It is the direct, maintained replacement for react-qr-reader, offering better performance, active community support, and compatibility with current browser media stream standards. Select this package if you require a reliable, drop-in solution for scanning functionality without the technical debt of deprecated dependencies.
A
npm i react-qr-code
When using this library with React Native, you will also need to have react-native-svg installed.
npm i react-native-svg
cd ios && pod install
import React from "react";
import ReactDOM from "react-dom";
import QRCode from "react-qr-code";
ReactDOM.render(<QRCode value="hey" />, document.getElementById("Container"));
Note: If the QR code is likely to appear next to dark objects, you will need to wrap it in a light-colored container to preserve the 'quiet zone', e.g.
<div style={{ background: 'white', padding: '16px' }}>
<QRCode ... />
</div>
Responsive QR code example:
// Can be anything instead of `maxWidth` that limits the width.
<div style={{ height: "auto", margin: "0 auto", maxWidth: 64, width: "100%" }}>
<QRCode
size={256}
style={{ height: "auto", maxWidth: "100%", width: "100%" }}
value={value}
viewBox={`0 0 256 256`}
/>
</div>
| prop | type | default value | platform |
|---|---|---|---|
bgColor | string | '#FFFFFF' | web, ios, android |
fgColor | string | '#000000' | web, ios, android |
level | string ('L' 'M' 'Q' 'H') | 'L' | web, ios, android |
size | number | 256 | web, ios, android |
title | string | web | |
value | string | web, ios, android |
Adheres to the official QR spec and can store up to 2953 characters in value.
react-qr-code encodes data in UTF-8 byte mode to ensure non-ASCII text (e.g., Korean, Japanese, emoji) renders and scans correctly. Just pass a normal JavaScript string:
<QRCode value="νκΈ ν
μ€νΈ π" />
No additional encoding is required on your side.
npm run demo-web-watchnpm run demoμλ
νμΈμ,
γγγ«γ‘γ―, or an emoji) into the input.MIT