search
React star Featured

QR Codes with React: Quick Implementation

Build QR code scanner and generator in React. Simple setup with react-qr-code and html5-qrcode libraries.

person By Gautam Sharma
calendar_today December 31, 2024
schedule 5 min read
React QR Code JavaScript

Quick guide to adding QR code functionality in React apps. No backend needed.

Install Libraries

npm install react-qr-code html5-qrcode

Generate QR Codes

import { QRCodeSVG } from 'react-qr-code';
import { useState } from 'react';

export default function QRGenerator() {
  const [text, setText] = useState('https://example.com');

  return (
    <div style={{ padding: '20px', textAlign: 'center' }}>
      <input
        type="text"
        value={text}
        onChange={(e) => setText(e.target.value)}
        placeholder="Enter text or URL"
        style={{
          width: '100%',
          maxWidth: '400px',
          padding: '12px',
          marginBottom: '20px',
          border: '2px solid #ddd',
          borderRadius: '8px',
          fontSize: '16px'
        }}
      />

      {text && (
        <QRCodeSVG
          value={text}
          size={256}
          level="M"
          style={{ margin: '0 auto' }}
        />
      )}
    </div>
  );
}

Download QR Code

import { QRCodeCanvas } from 'react-qr-code';
import { useRef } from 'react';

export default function DownloadableQR() {
  const qrRef = useRef();
  const [value, setValue] = useState('https://example.com');

  const downloadQR = () => {
    const canvas = qrRef.current.querySelector('canvas');
    const url = canvas.toDataURL('image/png');
    const link = document.createElement('a');
    link.download = 'qrcode.png';
    link.href = url;
    link.click();
  };

  return (
    <div>
      <input
        value={value}
        onChange={(e) => setValue(e.target.value)}
        placeholder="Enter URL"
      />

      <div ref={qrRef}>
        <QRCodeCanvas value={value} size={300} />
      </div>

      <button onClick={downloadQR}>Download PNG</button>
    </div>
  );
}

Scan QR Codes

import { useEffect, useState } from 'react';
import { Html5QrcodeScanner } from 'html5-qrcode';

export default function QRScanner() {
  const [scanResult, setScanResult] = useState('');

  useEffect(() => {
    const scanner = new Html5QrcodeScanner(
      'reader',
      { fps: 10, qrbox: { width: 250, height: 250 } },
      false
    );

    scanner.render(
      (decodedText) => {
        setScanResult(decodedText);
        scanner.clear();
      },
      (error) => {
        console.warn(error);
      }
    );

    return () => {
      scanner.clear().catch(console.error);
    };
  }, []);

  return (
    <div style={{ maxWidth: '600px', margin: '0 auto' }}>
      <div id="reader"></div>

      {scanResult && (
        <div style={{
          marginTop: '20px',
          padding: '15px',
          background: '#f0f9ff',
          borderRadius: '8px'
        }}>
          <strong>Scanned:</strong>
          <p>{scanResult}</p>
        </div>
      )}
    </div>
  );
}

Scan from Image File

import { Html5Qrcode } from 'html5-qrcode';

export default function FileScan() {
  const [result, setResult] = useState('');

  const handleFile = async (e) => {
    const file = e.target.files[0];
    if (!file) return;

    const scanner = new Html5Qrcode('reader');
    try {
      const text = await scanner.scanFile(file, true);
      setResult(text);
    } catch (err) {
      console.error('Scan failed:', err);
    }
  };

  return (
    <div>
      <input type="file" accept="image/*" onChange={handleFile} />
      {result && <p>Result: {result}</p>}
    </div>
  );
}

Combined Component

import { QRCodeSVG } from 'react-qr-code';
import { Html5QrcodeScanner } from 'html5-qrcode';
import { useState, useEffect } from 'react';

export default function QRApp() {
  const [mode, setMode] = useState('generate');
  const [text, setText] = useState('');
  const [scanResult, setScanResult] = useState('');

  useEffect(() => {
    if (mode === 'scan') {
      const scanner = new Html5QrcodeScanner('reader', { fps: 10 }, false);
      scanner.render(
        (result) => {
          setScanResult(result);
          scanner.clear();
        },
        console.warn
      );
      return () => scanner.clear().catch(console.error);
    }
  }, [mode]);

  return (
    <div style={{ padding: '20px', maxWidth: '600px', margin: '0 auto' }}>
      <div style={{ display: 'flex', gap: '10px', marginBottom: '20px' }}>
        <button
          onClick={() => setMode('generate')}
          style={{
            flex: 1,
            padding: '12px',
            background: mode === 'generate' ? '#007bff' : '#fff',
            color: mode === 'generate' ? '#fff' : '#000',
            border: '2px solid #007bff',
            borderRadius: '8px',
            cursor: 'pointer'
          }}
        >
          Generate
        </button>
        <button
          onClick={() => setMode('scan')}
          style={{
            flex: 1,
            padding: '12px',
            background: mode === 'scan' ? '#007bff' : '#fff',
            color: mode === 'scan' ? '#fff' : '#000',
            border: '2px solid #007bff',
            borderRadius: '8px',
            cursor: 'pointer'
          }}
        >
          Scan
        </button>
      </div>

      {mode === 'generate' ? (
        <div>
          <input
            value={text}
            onChange={(e) => setText(e.target.value)}
            placeholder="Enter text"
            style={{
              width: '100%',
              padding: '12px',
              marginBottom: '20px',
              border: '2px solid #ddd',
              borderRadius: '8px'
            }}
          />
          {text && (
            <div style={{ textAlign: 'center' }}>
              <QRCodeSVG value={text} size={256} />
            </div>
          )}
        </div>
      ) : (
        <div>
          <div id="reader"></div>
          {scanResult && (
            <div style={{
              marginTop: '20px',
              padding: '15px',
              background: '#d4edda',
              borderRadius: '8px'
            }}>
              <strong>Result:</strong> {scanResult}
            </div>
          )}
        </div>
      )}
    </div>
  );
}

Custom Hook

import { useState, useEffect } from 'react';
import { Html5QrcodeScanner } from 'html5-qrcode';

export function useQRScanner(readerId = 'reader') {
  const [result, setResult] = useState('');
  const [isScanning, setIsScanning] = useState(false);

  const startScan = () => {
    setIsScanning(true);
    const scanner = new Html5QrcodeScanner(readerId, { fps: 10 }, false);

    scanner.render(
      (text) => {
        setResult(text);
        scanner.clear();
        setIsScanning(false);
      },
      console.warn
    );
  };

  return { result, isScanning, startScan };
}

WiFi QR Code

import { QRCodeSVG } from 'react-qr-code';
import { useState } from 'react';

export default function WiFiQR() {
  const [ssid, setSsid] = useState('');
  const [password, setPassword] = useState('');
  const [encryption, setEncryption] = useState('WPA');

  const wifiString = ssid
    ? `WIFI:T:${encryption};S:${ssid};P:${password};;`
    : '';

  return (
    <div>
      <input
        value={ssid}
        onChange={(e) => setSsid(e.target.value)}
        placeholder="Network Name"
      />
      <input
        type="password"
        value={password}
        onChange={(e) => setPassword(e.target.value)}
        placeholder="Password"
      />
      <select value={encryption} onChange={(e) => setEncryption(e.target.value)}>
        <option value="WPA">WPA/WPA2</option>
        <option value="WEP">WEP</option>
        <option value="nopass">No Password</option>
      </select>

      {wifiString && (
        <QRCodeSVG value={wifiString} size={256} level="H" />
      )}
    </div>
  );
}

vCard Contact QR

const vcard = `BEGIN:VCARD
VERSION:3.0
FN:John Doe
TEL:+1234567890
EMAIL:john@example.com
END:VCARD`;

<QRCodeSVG value={vcard} size={256} level="M" />

Styling Options

<QRCodeSVG
  value="https://example.com"
  size={256}
  bgColor="#ffffff"
  fgColor="#000000"
  level="L"
  includeMargin={true}
/>

Error Correction Levels:

  • L: 7% damage tolerance
  • M: 15% (recommended)
  • Q: 25%
  • H: 30% (use with logos)

Camera Permissions

Handle permission errors in your scanner:

useEffect(() => {
  const scanner = new Html5QrcodeScanner('reader', { fps: 10 }, false);

  scanner.render(
    onSuccess,
    (error) => {
      if (error.includes('NotAllowedError')) {
        alert('Camera permission denied');
      }
    }
  );
}, []);

Key Points

  • Use react-qr-code for generation (SVG or Canvas)
  • Use html5-qrcode for scanning
  • Always cleanup scanner in useEffect return
  • Handle camera permissions gracefully
  • Use level H for QR codes with logos
  • Minimum size 200x200px for reliable scanning

Quick Start

// Install
npm install react-qr-code html5-qrcode

// Generate
import { QRCodeSVG } from 'react-qr-code';
<QRCodeSVG value="text" size={256} />

// Scan
import { Html5QrcodeScanner } from 'html5-qrcode';
const scanner = new Html5QrcodeScanner('id', { fps: 10 }, false);
scanner.render(onSuccess, onError);

That’s it. Two libraries handle everything QR code related in React.

Gautam Sharma

About Gautam Sharma

Full-stack developer and tech blogger sharing coding tutorials and best practices

Related Articles

React

Getting Started with React Hooks in 2025

Learn how to use React Hooks effectively in your modern React applications with practical examples and best practices.

December 15, 2024
React

How to integrate jsPDF Library in React to Edit PDF in Browser

Quick guide to using jsPDF in React applications for creating and editing PDF documents directly in the browser.

December 29, 2024
JavaScript

How to Integrate Mozilla PDF.js in HTML: Build a PDF Viewer in Browser

Quick guide to integrating Mozilla PDF.js into your HTML application to build a functional PDF viewer directly in the browser.

December 31, 2024