search
Angular star Featured

Generate and Scan QR Codes in Angular

Quick guide to generating and scanning QR codes in Angular browser applications. Simple examples with ngx-qrcode and html5-qrcode.

person By Gautam Sharma
calendar_today December 31, 2024
schedule 7 min read
Angular QR Code Browser Scanner

QR codes are essential for modern web apps. Here’s how to generate and scan them in Angular.

Installation

npm install @techiediaries/ngx-qrcode
npm install html5-qrcode

Generate QR Codes

Setup Module

// app.config.ts (Angular 17+)
import { ApplicationConfig } from '@angular/core';
import { provideRouter } from '@angular/router';

export const appConfig: ApplicationConfig = {
  providers: [
    provideRouter(routes)
  ]
};

Component Setup

// qr-generator.component.ts
import { Component } from '@angular/core';
import { NgxQRCodeModule } from '@techiediaries/ngx-qrcode';
import { FormsModule } from '@angular/forms';

@Component({
  selector: 'app-qr-generator',
  standalone: true,
  imports: [NgxQRCodeModule, FormsModule],
  templateUrl: './qr-generator.component.html',
  styleUrls: ['./qr-generator.component.css']
})
export class QrGeneratorComponent {
  qrData: string = 'https://example.com';
  qrWidth: number = 256;
}

Template

<!-- qr-generator.component.html -->
<div class="qr-container">
  <h2>Generate QR Code</h2>

  <input
    type="text"
    [(ngModel)]="qrData"
    placeholder="Enter text or URL"
    class="input-field"
  />

  <ngx-qrcode
    [value]="qrData"
    [width]="qrWidth"
    errorCorrectionLevel="M"
    cssClass="qr-code"
  ></ngx-qrcode>

  <button (click)="downloadQR()">Download QR Code</button>
</div>

Download QR Code

// qr-generator.component.ts
downloadQR() {
  const canvas = document.querySelector('canvas') as HTMLCanvasElement;
  if (canvas) {
    const url = canvas.toDataURL('image/png');
    const link = document.createElement('a');
    link.download = 'qrcode.png';
    link.href = url;
    link.click();
  }
}

Scan QR Codes

Scanner Component

// qr-scanner.component.ts
import { Component, OnInit, OnDestroy } from '@angular/core';
import { Html5QrcodeScanner } from 'html5-qrcode';
import { CommonModule } from '@angular/common';

@Component({
  selector: 'app-qr-scanner',
  standalone: true,
  imports: [CommonModule],
  templateUrl: './qr-scanner.component.html',
  styleUrls: ['./qr-scanner.component.css']
})
export class QrScannerComponent implements OnInit, OnDestroy {
  private scanner: Html5QrcodeScanner | null = null;
  scannedResult: string = '';
  isScanning: boolean = false;

  ngOnInit() {
    this.initScanner();
  }

  initScanner() {
    this.scanner = new Html5QrcodeScanner(
      'qr-reader',
      {
        fps: 10,
        qrbox: { width: 250, height: 250 }
      },
      false
    );

    this.scanner.render(
      (decodedText) => this.onScanSuccess(decodedText),
      (error) => this.onScanError(error)
    );

    this.isScanning = true;
  }

  onScanSuccess(decodedText: string) {
    this.scannedResult = decodedText;
    console.log('QR Code scanned:', decodedText);

    // Stop scanning after successful scan
    if (this.scanner) {
      this.scanner.clear();
      this.isScanning = false;
    }
  }

  onScanError(error: any) {
    // Handle scan error silently
    console.warn('Scan error:', error);
  }

  restartScanner() {
    this.scannedResult = '';
    this.initScanner();
  }

  ngOnDestroy() {
    if (this.scanner) {
      this.scanner.clear();
    }
  }
}

Scanner Template

<!-- qr-scanner.component.html -->
<div class="scanner-container">
  <h2>Scan QR Code</h2>

  <div id="qr-reader"></div>

  <div *ngIf="scannedResult" class="result">
    <h3>Scanned Result:</h3>
    <p>{{ scannedResult }}</p>
    <button (click)="restartScanner()">Scan Again</button>
  </div>
</div>

Styling

/* qr-generator.component.css */
.qr-container {
  max-width: 500px;
  margin: 0 auto;
  padding: 20px;
  text-align: center;
}

.input-field {
  width: 100%;
  padding: 12px;
  margin: 20px 0;
  border: 2px solid #ddd;
  border-radius: 8px;
  font-size: 16px;
}

.qr-code {
  margin: 20px 0;
  padding: 20px;
  background: white;
  border-radius: 8px;
  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}

button {
  padding: 12px 24px;
  background: #007bff;
  color: white;
  border: none;
  border-radius: 8px;
  cursor: pointer;
  font-size: 16px;
}

button:hover {
  background: #0056b3;
}
/* qr-scanner.component.css */
.scanner-container {
  max-width: 600px;
  margin: 0 auto;
  padding: 20px;
}

#qr-reader {
  border: 2px solid #ddd;
  border-radius: 8px;
  overflow: hidden;
  margin: 20px 0;
}

.result {
  margin-top: 20px;
  padding: 20px;
  background: #f0f9ff;
  border-radius: 8px;
  border: 2px solid #007bff;
}

.result h3 {
  margin: 0 0 10px 0;
  color: #007bff;
}

.result p {
  word-break: break-all;
  padding: 10px;
  background: white;
  border-radius: 4px;
  margin: 10px 0;
}

Combined Component

// qr-manager.component.ts
import { Component } from '@angular/core';
import { QrGeneratorComponent } from './qr-generator.component';
import { QrScannerComponent } from './qr-scanner.component';
import { CommonModule } from '@angular/common';

@Component({
  selector: 'app-qr-manager',
  standalone: true,
  imports: [CommonModule, QrGeneratorComponent, QrScannerComponent],
  template: `
    <div class="qr-manager">
      <div class="tabs">
        <button
          [class.active]="activeTab === 'generate'"
          (click)="activeTab = 'generate'">
          Generate QR Code
        </button>
        <button
          [class.active]="activeTab === 'scan'"
          (click)="activeTab = 'scan'">
          Scan QR Code
        </button>
      </div>

      <app-qr-generator *ngIf="activeTab === 'generate'"></app-qr-generator>
      <app-qr-scanner *ngIf="activeTab === 'scan'"></app-qr-scanner>
    </div>
  `,
  styles: [`
    .qr-manager {
      max-width: 800px;
      margin: 0 auto;
      padding: 20px;
    }

    .tabs {
      display: flex;
      gap: 10px;
      margin-bottom: 20px;
    }

    .tabs button {
      flex: 1;
      padding: 12px;
      border: 2px solid #ddd;
      background: white;
      cursor: pointer;
      border-radius: 8px;
      font-size: 16px;
    }

    .tabs button.active {
      background: #007bff;
      color: white;
      border-color: #007bff;
    }
  `]
})
export class QrManagerComponent {
  activeTab: 'generate' | 'scan' = 'generate';
}
// qr-with-logo.component.ts
import { Component } from '@angular/core';
import { NgxQRCodeModule } from '@techiediaries/ngx-qrcode';
import { FormsModule } from '@angular/forms';

@Component({
  selector: 'app-qr-with-logo',
  standalone: true,
  imports: [NgxQRCodeModule, FormsModule],
  template: `
    <div class="qr-logo-container">
      <input
        type="text"
        [(ngModel)]="qrData"
        placeholder="Enter URL"
      />

      <div class="qr-wrapper">
        <ngx-qrcode
          [value]="qrData"
          [width]="300"
          errorCorrectionLevel="H"
        ></ngx-qrcode>
        <img
          src="/logo.png"
          alt="Logo"
          class="qr-logo"
        />
      </div>
    </div>
  `,
  styles: [`
    .qr-wrapper {
      position: relative;
      display: inline-block;
    }

    .qr-logo {
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      width: 60px;
      height: 60px;
      background: white;
      padding: 5px;
      border-radius: 8px;
    }
  `]
})
export class QrWithLogoComponent {
  qrData: string = 'https://example.com';
}

Dynamic QR Code Generation

// dynamic-qr.component.ts
import { Component } from '@angular/core';
import { NgxQRCodeModule } from '@techiediaries/ngx-qrcode';
import { FormsModule } from '@angular/forms';

@Component({
  selector: 'app-dynamic-qr',
  standalone: true,
  imports: [NgxQRCodeModule, FormsModule],
  template: `
    <div class="dynamic-qr">
      <h3>Generate vCard QR Code</h3>

      <input [(ngModel)]="name" placeholder="Name" />
      <input [(ngModel)]="phone" placeholder="Phone" />
      <input [(ngModel)]="email" placeholder="Email" />

      <button (click)="generateVCard()">Generate vCard</button>

      <ngx-qrcode
        *ngIf="vCardData"
        [value]="vCardData"
        [width]="256"
      ></ngx-qrcode>
    </div>
  `
})
export class DynamicQrComponent {
  name: string = '';
  phone: string = '';
  email: string = '';
  vCardData: string = '';

  generateVCard() {
    this.vCardData = `BEGIN:VCARD
VERSION:3.0
FN:${this.name}
TEL:${this.phone}
EMAIL:${this.email}
END:VCARD`;
  }
}

WiFi QR Code

// wifi-qr.component.ts
import { Component } from '@angular/core';
import { NgxQRCodeModule } from '@techiediaries/ngx-qrcode';
import { FormsModule } from '@angular/forms';

@Component({
  selector: 'app-wifi-qr',
  standalone: true,
  imports: [NgxQRCodeModule, FormsModule],
  template: `
    <div class="wifi-qr">
      <h3>WiFi QR Code</h3>

      <input [(ngModel)]="ssid" placeholder="Network Name (SSID)" />
      <input [(ngModel)]="password" type="password" placeholder="Password" />
      <select [(ngModel)]="encryption">
        <option value="WPA">WPA/WPA2</option>
        <option value="WEP">WEP</option>
        <option value="nopass">No Password</option>
      </select>

      <button (click)="generateWiFiQR()">Generate</button>

      <ngx-qrcode
        *ngIf="wifiData"
        [value]="wifiData"
        [width]="256"
      ></ngx-qrcode>
    </div>
  `
})
export class WifiQrComponent {
  ssid: string = '';
  password: string = '';
  encryption: string = 'WPA';
  wifiData: string = '';

  generateWiFiQR() {
    this.wifiData = `WIFI:T:${this.encryption};S:${this.ssid};P:${this.password};;`;
  }
}

Scan from File

// file-scanner.component.ts
import { Component } from '@angular/core';
import { Html5Qrcode } from 'html5-qrcode';
import { CommonModule } from '@angular/common';

@Component({
  selector: 'app-file-scanner',
  standalone: true,
  imports: [CommonModule],
  template: `
    <div class="file-scanner">
      <h3>Scan QR from Image File</h3>

      <input
        type="file"
        accept="image/*"
        (change)="onFileSelected($event)"
      />

      <div *ngIf="result" class="result">
        <h4>Result:</h4>
        <p>{{ result }}</p>
      </div>

      <div *ngIf="error" class="error">
        {{ error }}
      </div>
    </div>
  `,
  styles: [`
    .result {
      margin-top: 20px;
      padding: 15px;
      background: #d4edda;
      border-radius: 8px;
    }

    .error {
      margin-top: 20px;
      padding: 15px;
      background: #f8d7da;
      border-radius: 8px;
      color: #721c24;
    }
  `]
})
export class FileScannerComponent {
  result: string = '';
  error: string = '';

  async onFileSelected(event: any) {
    const file = event.target.files[0];
    if (!file) return;

    const html5QrCode = new Html5Qrcode('reader');

    try {
      const result = await html5QrCode.scanFile(file, true);
      this.result = result;
      this.error = '';
    } catch (err) {
      this.error = 'Failed to scan QR code from image';
      this.result = '';
    }
  }
}

Routes Setup

// app.routes.ts
import { Routes } from '@angular/router';
import { QrManagerComponent } from './qr-manager.component';

export const routes: Routes = [
  { path: '', redirectTo: '/qr', pathMatch: 'full' },
  { path: 'qr', component: QrManagerComponent }
];

Permissions

Camera access requires HTTPS in production. Add to angular.json for development:

{
  "serve": {
    "options": {
      "ssl": true
    }
  }
}

Error Handling

// scanner-with-errors.component.ts
handlePermissionError() {
  alert('Camera permission denied. Please enable camera access.');
}

handleCameraError(error: any) {
  if (error.name === 'NotAllowedError') {
    this.handlePermissionError();
  } else if (error.name === 'NotFoundError') {
    alert('No camera found on this device.');
  } else {
    alert('Error accessing camera: ' + error.message);
  }
}

Best Practices

  1. Error Correction: Use ‘H’ level for QR codes with logos (30% damage tolerance)
  2. Size: Minimum 256x256px for reliable scanning
  3. Contrast: Dark QR on light background works best
  4. Testing: Test on multiple devices and lighting conditions
  5. Permissions: Always handle camera permission errors gracefully
  6. Cleanup: Clear scanner in ngOnDestroy to prevent memory leaks

Quick Reference

Generate QR:

<ngx-qrcode
  [value]="data"
  [width]="256"
  errorCorrectionLevel="M"
></ngx-qrcode>

Scan QR:

const scanner = new Html5QrcodeScanner('reader', { fps: 10 }, false);
scanner.render(onSuccess, onError);

Download QR:

const canvas = document.querySelector('canvas');
const url = canvas.toDataURL('image/png');

Special Formats:

  • URL: https://example.com
  • WiFi: WIFI:T:WPA;S:NetworkName;P:Password;;
  • vCard: BEGIN:VCARD\nVERSION:3.0\n...
  • SMS: SMSTO:+1234567890:Hello
  • Email: mailto:test@example.com

Conclusion

Angular makes QR code generation and scanning straightforward with ngx-qrcode and html5-qrcode. Both libraries work reliably in the browser without backend dependencies.

Gautam Sharma

About Gautam Sharma

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

Related Articles

Angular

Angular 21 jsPDF Example to Edit & Modify PDF Files in Browser

Learn how to integrate jsPDF with Angular 21 to create, edit, and modify PDF documents directly in the browser using standalone components and signals.

December 30, 2024
Vue

Vue.js Scan & Generate QRCodes in Browser

Quick guide to generating and scanning QR codes in Vue.js browser applications. Simple examples with qrcode.vue and html5-qrcode.

December 31, 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