Skip to content

fix(frontend): Improve QR scanning reliability for dark borderless codes#12162

Merged
AntonioVentilii merged 5 commits intomainfrom
fix-frontend/Improve-QR-scanning-reliability-for-dark-borderless-codes
Mar 25, 2026
Merged

fix(frontend): Improve QR scanning reliability for dark borderless codes#12162
AntonioVentilii merged 5 commits intomainfrom
fix-frontend/Improve-QR-scanning-reliability-for-dark-borderless-codes

Conversation

@AntonioVentilii
Copy link
Copy Markdown
Collaborator

@AntonioVentilii AntonioVentilii commented Mar 25, 2026

Note

This PR is a fork of dfinity/gix-components#759.

Awaiting that review, we simply copy the components in our repo and add it to the next release, since it is a time-sensitive issue.

Motivation

The QR code reader was using html5-qrcode, which has a known issue with inverted (dark-themed, borderless) QR codes on mobile — they simply cannot be scanned. The library is also unmaintained.

Known upstream issues:

Since the root cause is a limitation of html5-qrcode itself (no support for inverted QR codes), and the library is no longer maintained, this PR replaces it with barcode-detector — a Barcode Detection API polyfill powered by ZXing C++ WebAssembly under the hood. The underlying engine natively supports inverted code detection (tryInvert is enabled by default). We tested it manually on a mobile device and dark borderless QR codes are now successfully scanned.

Thanks to @sea-snake for the tip!

Changes (copied from gix-components's QRCodeReader)

  • Removed the html5-qrcode dependency entirely in component QRCodeReader.
  • In component QRCodeReader:
    • Camera access is now handled directly via the browser navigator.mediaDevices.getUserMedia API, requesting the rear-facing camera (facingMode: "environment") at up to 1920×1080 resolution.
    • The video feed is rendered in a native <video> element.
    • QR decoding uses the standard BarcodeDetector API (via barcode-detector/ponyfill). A detector instance is created with formats: ["qr_code"] and detector.detect(videoElement) is called at ~10 fps via setInterval(scan, 100). The polyfill accepts the <video> element directly — no intermediate <canvas> needed.
    • A frame-processing guard (isProcessingFrame) prevents overlapping decode calls.
    • Cleanup on destroy properly clears the scan interval and stops all media tracks.
    • The scan overlay is now implemented with a .scan-overlay container with a .scan-region box using box-shadow to mask the surrounding area and a border styled with the primary color. This replaces the old :global(#qr-shaded-region) overrides that targeted html5-qrcode's internal DOM.
  • Updated the library reference in the QR code reader docs page from jsQR to barcode-detector.
  • Added barcode-detector@^3.1.1 to dependencies and removed html5-qrcode.

Tests

Manual testing on mobile: dark borderless QR codes are now successfully scanned (this was the main validation, as the core issue only reproduced on real mobile devices).

IMG_5315 IMG_5314

@AntonioVentilii AntonioVentilii marked this pull request as ready for review March 25, 2026 13:05
@AntonioVentilii AntonioVentilii requested a review from a team as a code owner March 25, 2026 13:05
Copilot AI review requested due to automatic review settings March 25, 2026 13:05
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR replaces the existing QR scanning implementation (previously sourced from @dfinity/gix-components / html5-qrcode) with a locally vendored QRCodeReader that uses the barcode-detector ponyfill (ZXing WASM) to improve scanning reliability for inverted/dark borderless QR codes, especially on mobile.

Changes:

  • Added a new local QRCodeReader.svelte that uses getUserMedia + barcode-detector/ponyfill to decode QR codes from a <video> stream.
  • Updated WalletConnect and general QR scanning flows to use the local QRCodeReader instead of @dfinity/gix-components.
  • Added a small nextElementId utility and introduced barcode-detector as a dependency.

Reviewed changes

Copilot reviewed 5 out of 6 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/frontend/src/lib/utils/html.utils.ts Adds an element-id helper used by the new QR code reader.
src/frontend/src/lib/components/wallet-connect/WalletConnectForm.svelte Switches to the local QR code reader component.
src/frontend/src/lib/components/ui/QRCodeReader.svelte New QR scanning component using getUserMedia + barcode-detector ponyfill.
src/frontend/src/lib/components/qr/QrCodeScanner.svelte Switches to the local QR code reader component.
package.json Adds barcode-detector dependency.
package-lock.json Lockfile updates for the new dependency tree.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@AntonioVentilii AntonioVentilii added this pull request to the merge queue Mar 25, 2026
Merged via the queue into main with commit a204b64 Mar 25, 2026
81 checks passed
@AntonioVentilii AntonioVentilii deleted the fix-frontend/Improve-QR-scanning-reliability-for-dark-borderless-codes branch March 25, 2026 14:56
github-merge-queue bot pushed a commit that referenced this pull request Mar 25, 2026
# Motivation

To use the new library from `QrCodeReader` component (PR
#12162) we need to allow it
in the CSP.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants