@yudiel/react-qr-scanner

repository·main·Indexed 19 days ago

https://github.com/yudielcurbelo/react-qr-scanner

A modern React library for scanning QR codes and barcodes using the device camera or webcam, built on top of the Barcode Detection API. It provides a Scanner component with support for custom camera constraints, specific barcode format filtering, audio feedback, and custom tracking overlays. Includes the useDevices hook for camera selection and isBarcodeDetectorSupported() to check for native API support.

Tokens
8.2K
Snippets
25
Records
40
Agent score
63%

What's inside @yudiel/react-qr-scanner

  1. Understand library limitations

    main

    When integrating @yudiel/react-qr-scanner, be aware of the following constraints:

    • Security: Requires HTTPS or localhost due to browser security restrictions.
    • iOS Audio: The first scan after page load may not play a beep sound due to iOS user-gesture requirements.
    • SSR: The library is not compatible with Server-Side Rendering; it must be loaded on the client side.
    • Mobile Hardware: Some mobile browsers cannot use the torch and zoom features at the same time. The library handles this by disabling the torch when zoom is activated.
  2. Quick Start with the Scanner component

    main

    To implement a basic scanner, import the Scanner component and provide onScan and onError callbacks. The onScan callback receives the detected results, and onError handles scanning errors.

    import { Scanner } from '@yudiel/react-qr-scanner';
    
    function App() {
      return (
        <Scanner
          onScan={(result) => console.log(result)}
          onError={(error) => console.log(error?.message)}
        />
      );
    }
  3. Handle iOS Safari audio and torch/zoom limitations

    main

    Audio on iOS

    iOS Safari requires a user gesture before audio can play. The very first scan after page load might be silent; subsequent scans after user interaction will play sound normally.

    Torch and Zoom

    Mobile browsers cannot use ImageCapture (torch) and non-ImageCapture (zoom) constraints simultaneously. When you apply a zoom, the library automatically disables the torch. To use both, re-toggle the torch after the zoom change has settled.

  4. Troubleshoot scanning and detection issues

    main

    If the scanner is running but not detecting codes:

    • Ensure adequate lighting and camera focus.
    • Try removing the formats prop to allow detection of all supported formats.
    • WASM Polyfill issues: If isBarcodeDetectorSupported() is false, the library uses a WASM polyfill. If you see a 404 in the Network tab for the WASM file, you must host it correctly using prepareZXingModule({ overrides: { locateFile } }).
  5. Troubleshoot camera permission and device errors

    main

    The onError callback provides a kind property that identifies common camera access issues. Use these to surface appropriate UI messages to the user:

    • permission-denied: The user denied camera access. Instruct them to re-grant permission in browser settings (e.g., Chrome site-info chip or Safari Website settings).
    • no-camera: No video input devices were found. Check if a camera is connected or if a previously used deviceId is no longer available. If using a deviceId, try omitting constraints.deviceId to fall back to facingMode.
    • in-use: The camera is locked by another application or tab. The user must close the other application and remount the Scanner.
    • overconstrained: The provided constraints (like width, height, or aspectRatio) cannot be satisfied by the hardware. Try removing the conflicting constraint.
    • insecure-context: Camera APIs require a secure origin. Ensure the site is served over HTTPS or localhost.
  6. Fix Next.js and SSR build errors

    main

    Because this library relies on browser-only APIs, it will fail during Server-Side Rendering (SSR). To use it in Next.js, you must import the Scanner component lazily with ssr: false.

    Additionally, the useDevices() hook is browser-only and should only be called within 'use client' components or inside a dynamic wrapper.

    import dynamic from 'next/dynamic';
    
    const Scanner = dynamic(
      () => import('@yudiel/react-qr-scanner').then((m) => m.Scanner),
      { ssr: false },
    );
  7. Filter scanning by specific barcode formats

    main

    You can restrict the scanner to specific formats using the formats prop. This accepts BarcodeFormat values (e.g., 'qr_code', 'ean_13'). You can also use shorthand values like 'linear_codes' or 'matrix_codes' to detect groups of formats.

    <Scanner
      onScan={(result) => console.log(result)}
      formats={['qr_code', 'ean_13', 'code_128']}
    />
  8. Implement a Basic Scanner with detected code details

    main

    The onScan callback returns an array of IDetectedBarcode objects. You can access properties like format and rawValue for each detected code.

    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 (
        <Scanner
          onScan={handleScan}
          onError={(error) => console.error(error)}
        />
      );
    }
  9. Select specific cameras using the useDevices hook

    main

    Use the useDevices hook to retrieve a list of available camera devices. You can then pass a specific deviceId to the Scanner component via the constraints prop to switch between cameras.

    import { Scanner, useDevices } from '@yudiel/react-qr-scanner';
    import { useState } from 'react';
    
    function DeviceSelectionExample() {
      const devices = useDevices();
      const [selectedDevice, setSelectedDevice] = useState(null);
    
      return (
        <div>
          <select onChange={(e) => setSelectedDevice(e.target.value)}>
            <option value="">Select a camera</option>
            {devices.map((device) => (
              <option key={device.deviceId} value={device.deviceId}>
                {device.label || `Camera ${device.deviceId}`}
              </option>
            ))}
          </select>
    
          <Scanner
            onScan={(result) => console.log(result)}
            constraints={{
              deviceId: selectedDevice,
            }}
          />
        </div>
      );
    }
  10. Access the video element and stream using Scanner ref

    main

    The Scanner component is a forwardRef. You can pass a ref of type IScannerHandle to access the underlying HTMLVideoElement and the active MediaStream. This is useful for taking snapshots or manual video manipulation.

    import { Scanner, type IScannerHandle } from '@yudiel/react-qr-scanner';
    import { useRef } from 'react';
    
    function App() {
      const scannerRef = useRef<IScannerHandle>(null);
    
      function snapshot() {
        const video = scannerRef.current?.getVideoElement();
        if (!video) return;
        // ...take a still frame from the video element
      }
    
      return <Scanner ref={scannerRef} onScan={console.log} />;
    }
  11. Configure the Scanner component via props

    main

    The Scanner component accepts several props to control scanning behavior, UI, and error handling:

    • onScan: (Required) Callback function triggered when barcodes are detected. Receives an array of IDetectedBarcode objects.
    • onError: Callback for errors (e.g., camera failure). Receives an IScannerError object.
    • constraints: MediaTrackConstraints applied to the video stream (e.g., { facingMode: 'environment' }).
    • formats: Array of BarcodeFormat to detect. Defaults to all supported formats.
    • paused: Boolean to pause scanning and show the last frame.
    • scanDelay: Minimum ms between onScan calls when allowMultiple is true.
    • allowMultiple: If true, allows the same barcode to trigger onScan repeatedly.
    • sound: Boolean or string (URL/data URI) to play a beep on successful scan.
    • tracker: A TrackFunction to draw custom overlays on the scanner.
    • styles / classNames: Used to customize the CSS of the container, video, and finder.
    • retryDelay: Delay between detection attempts (defaults to 500ms or ~30fps with a tracker).