A library to scan QR codes in React.
npm install @yudiel/react-qr-scanner


A modern React library for scanning QR codes and barcodes using your device camera or webcam. Built on top of the Barcode Detection API with React hooks and components.
- Multiple Barcode Formats - Supports QR codes, EAN, UPC, Code 128, and many more 1D/2D formats
- Camera Controls - Built-in torch (flashlight), zoom, and camera switching capabilities
- Flexible Scanning - Continuous scanning, single scan mode, or pause/resume functionality
- Custom Tracking - Draw custom overlays and tracking visualizations on detected barcodes
- Device Selection - Choose specific cameras with the useDevices hook
- Customizable UI - Custom styles, class names, and component overrides
- Audio Feedback - Optional beep sound on successful scans (with custom sound support)
- TypeScript Support - Fully typed for excellent developer experience
- Lightweight - Minimal dependencies with optimized bundle size
- Cross-browser Compatible - Works across modern browsers with webrtc-adapter
- Demo
- Installation
- Quick Start
- Usage Examples
- Basic Scanner
- Device Selection
- Camera Constraints
- Custom Tracking Overlay
- Pausing and Resuming
- UI Components
- API Reference
- Scanner Props
- useDevices Hook
- Supported Formats
- Type Definitions
- Browser Support
- Limitations
- Contributing
- License
Check out the live demo to see the scanner in action.
``bash`
npm install @yudiel/react-qr-scanner
`bash`
yarn add @yudiel/react-qr-scanner
`bash`
pnpm add @yudiel/react-qr-scanner
`jsx
import { Scanner } from '@yudiel/react-qr-scanner';
function App() {
return (
onError={(error) => console.log(error?.message)}
/>
);
}
`
`jsx
import { Scanner } from '@yudiel/react-qr-scanner';
function BasicExample() {
const handleScan = (detectedCodes) => {
console.log('Detected codes:', detectedCodes);
// detectedCodes is an array of IDetectedBarcode objects
detectedCodes.forEach(code => {
console.log(Format: ${code.format}, Value: ${code.rawValue});
});
};
return (
onError={(error) => console.error(error)}
/>
);
}
`
Use the useDevices hook to list available cameras and select a specific device:
`jsx
import { Scanner, useDevices } from '@yudiel/react-qr-scanner';
import { useState } from 'react';
function DeviceSelectionExample() {
const devices = useDevices();
const [selectedDevice, setSelectedDevice] = useState(null);
return (
constraints={{
deviceId: selectedDevice,
}}
/>
$3
Customize camera settings using MediaTrackConstraints:
`jsx
import { Scanner } from '@yudiel/react-qr-scanner';function ConstraintsExample() {
return (
onScan={(result) => console.log(result)}
constraints={{
facingMode: 'environment', // Use rear camera
aspectRatio: 1, // Square aspect ratio
// Advanced constraints
width: { ideal: 1920 },
height: { ideal: 1080 },
}}
/>
);
}
`$3
Draw custom visualizations on detected barcodes:
`jsx
import { Scanner } from '@yudiel/react-qr-scanner';function TrackingExample() {
const highlightCodeOnCanvas = (detectedCodes, ctx) => {
detectedCodes.forEach((detectedCode) => {
const { boundingBox, cornerPoints } = detectedCode;
// Draw bounding box
ctx.strokeStyle = '#00FF00';
ctx.lineWidth = 4;
ctx.strokeRect(
boundingBox.x,
boundingBox.y,
boundingBox.width,
boundingBox.height
);
// Draw corner points
ctx.fillStyle = '#FF0000';
cornerPoints.forEach((point) => {
ctx.beginPath();
ctx.arc(point.x, point.y, 5, 0, 2 * Math.PI);
ctx.fill();
});
});
};
return (
onScan={(result) => console.log(result)}
components={{
tracker: highlightCodeOnCanvas,
}}
/>
);
}
`$3
Control when the scanner is active:
`jsx
import { Scanner } from '@yudiel/react-qr-scanner';
import { useState } from 'react';function PauseExample() {
const [isPaused, setIsPaused] = useState(false);
return (
onScan={(result) => console.log(result)}
paused={isPaused}
/>
);
}
`$3
Enable built-in UI controls for torch, zoom, and camera switching:
`jsx
import { Scanner } from '@yudiel/react-qr-scanner';function UIComponentsExample() {
return (
onScan={(result) => console.log(result)}
components={{
audio: true, // Play beep sound on scan
onOff: true, // Show camera on/off button
torch: true, // Show torch/flashlight button (if supported)
zoom: true, // Show zoom control (if supported)
finder: true, // Show finder overlay
}}
// Custom sound (base64 encoded audio)
sound="data:audio/mp3;base64,YOUR_BASE64_AUDIO_HERE"
/>
);
}
`API Reference
$3
| Prop | Type | Required | Default | Description |
|-----------------|-----------------------------------------------|----------|---------|--------------------------------------------------------------------------------------------------|
|
onScan | (detectedCodes: IDetectedBarcode[]) => void | Yes | - | Callback function called when one or more barcodes are detected. |
| onError | (error: unknown) => void | No | - | Callback function called when an error occurs while accessing the camera. |
| constraints | MediaTrackConstraints | No | {} | Media track constraints to apply to the video stream (e.g., facingMode, deviceId). |
| formats | BarcodeFormat[] | No | All | Array of barcode formats to detect. If not specified, all supported formats are detected. |
| paused | boolean | No | false | If true, the scanner pauses and displays the last frame. |
| children | ReactNode | No | - | Custom children to render inside the scanner container. |
| components | IScannerComponents | No | {} | Configuration for built-in UI components and custom tracker function. |
| styles | IScannerStyles | No | {} | Custom CSS styles for scanner elements. |
| classNames | IScannerClassNames | No | {} | Custom CSS class names for scanner elements. |
| scanDelay | number | No | 500 | Delay in milliseconds between successful scans. Prevents duplicate detections. |
| allowMultiple | boolean | No | false | If true, allows the same barcode to trigger onScan multiple times. |
| sound | boolean \| string | No | false | If true, plays default beep sound. Provide a base64 audio string for custom sound. |$3
Returns an array of available video input devices (cameras).
`typescript
const devices = useDevices();
// Returns: MediaDeviceInfo[]
`Example:
`jsx
import { useDevices } from '@yudiel/react-qr-scanner';function CameraList() {
const devices = useDevices();
return (
{devices.map((device) => (
{device.label ||
Camera ${device.deviceId}}
))}
);
}
`Supported Formats
The library supports detection of the following barcode formats:
| 1D Barcodes | 2D Barcodes |
|------------------|---------------|
| Codabar | Aztec |
| Code 39 | Data Matrix |
| Code 93 | Matrix Codes |
| Code 128 | Maxi Code |
| Databar | Micro QR Code |
| Databar Expanded | PDF 417 |
| Dx Film Edge | QR Code |
| EAN 8 | rMQR Code |
| EAN 13 | |
| ITF | |
| Linear Codes | |
| UPC A | |
| UPC E | |
To detect specific formats only:
`jsx
onScan={(result) => console.log(result)}
formats={['qr_code', 'ean_13', 'code_128']}
/>
`Type Definitions
$3
`typescript
type BarcodeFormat =
| 'aztec'
| 'code_128'
| 'code_39'
| 'code_93'
| 'codabar'
| 'databar'
| 'databar_expanded'
| 'data_matrix'
| 'dx_film_edge'
| 'ean_13'
| 'ean_8'
| 'itf'
| 'maxi_code'
| 'micro_qr_code'
| 'pdf417'
| 'qr_code'
| 'rm_qr_code'
| 'upc_a'
| 'upc_e'
| 'linear_codes'
| 'matrix_codes'
| 'unknown';
`$3
`typescript
interface IDetectedBarcode {
boundingBox: IBoundingBox;
cornerPoints: IPoint[];
format: string;
rawValue: string;
}
`$3
`typescript
interface IBoundingBox {
x: number;
y: number;
width: number;
height: number;
}
`$3
`typescript
interface IPoint {
x: number;
y: number;
}
`$3
`typescript
interface IScannerComponents {
tracker?: TrackFunction;
onOff?: boolean;
torch?: boolean;
zoom?: boolean;
finder?: boolean;
}
`$3
`typescript
type TrackFunction = (
detectedCodes: IDetectedBarcode[],
ctx: CanvasRenderingContext2D
) => void;
`$3
`typescript
interface IScannerStyles {
container?: CSSProperties;
video?: CSSProperties;
finderBorder?: number;
}
`$3
`typescript
interface IScannerClassNames {
container?: string;
video?: string;
}
`Browser Support
This library requires support for:
- getUserMedia API - Camera access
- Barcode Detection API - Barcode scanning (polyfilled via barcode-detector)
- Canvas API - Drawing tracking overlays
Supported Browsers:
- Chrome/Edge 88+
- Firefox 90+ (with polyfill)
- Safari 14+ (with polyfill)
- Mobile browsers (iOS Safari 14.5+, Chrome Mobile)
The library uses
webrtc-adapter for cross-browser compatibility.Limitations
- HTTPS or localhost required - Due to browser security restrictions, camera access only works on secure contexts (HTTPS or localhost).
- iOS audio limitations - Beep sound on iOS Safari requires user interaction before playing. The first scan after page load may not play sound.
- Server-Side Rendering (SSR) - This library requires browser APIs and will not work during SSR. Ensure you only import and use it in client-side code:
`jsx
// Next.js example
import dynamic from 'next/dynamic'; const Scanner = dynamic(
() => import('@yudiel/react-qr-scanner').then((mod) => mod.Scanner),
{ ssr: false }
);
`- Mobile browser constraints - Some mobile browsers cannot use torch and zoom simultaneously. The library automatically disables torch when zoom is activated to prevent conflicts.
Contributing
Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
1. Fork the repository
2. Create your feature branch (
git checkout -b feature/amazing-feature)
3. Commit your changes (git commit -m 'Add some amazing feature')
4. Push to the branch (git push origin feature/amazing-feature`)