Simple QR Code Reader in SolidJS
This post is for those interested in implementing a QR Code scanner into your app using Solid as the front end. This tutorial creates a QR Code scanner without using the npm package.
Create solid project
To run Solid, make sure you have Node.js installed. Then, run one of these commands.
npx degit solidjs/templates/js simple-solid-qr-reader
cd simple-solid-qr-reader
npm install
npm run dev
If you get an error like this
Change Node.js version to v16.0.0 or v14.18.0. node: import support added in v16.0.0, v14.18.0. Check here.
After successfully installed, open it using your favorite editor. It will look like this:
Create a component
Create a QrReader.jsx
File and add a <video/> tag with an id and other attributes in the src folder with the following:
function QrReader() {
return (
<video id="video" width="640" height="480" autoplay></video>
)
}
export default QrReader
Next, we will select the video element from the component we just created and check if there is a camera available that we can use to stream:
import { onMount } from 'solid-js'
let videoEl = null
function QrReader() {
onMount(() => {
videoEl = document.querySelector('#video')
if (navigator.mediaDevices?.getUserMedia) {
const constraints = {
video: true,
audio: false
}
navigator.mediaDevices.getUserMedia(constraints).then(stream => videoEl.srcObject = stream);
}
});
return (
<video id="video" width="640" height="480" autoplay></video>
)
}
export default QrReader
Add Qr Reader component to src/App.jsx
import styles from './App.module.css'
import QrReader from './QrReader'
function App() {
return (
<div class={styles.App}>
<h1>QR Code Scanner</h1>
<QrReader />
</div>
)
}
export default App
Now, if you open the browser, you will see a live video stream that we can use to scan QR codes.
Barcode scanner functionality
Next, we will use BarcodeDetector, the interface of the Barcode Detection API. First, create a new BarcodeDetector class. Now we have BarcodeDetector class for making the barcode detector function. To start detecting barcodes we use the BarcodeDetector.detect() and run detect code function every 500 milliseconds.
For more detail about
BarcodeDetector
, check here.
Now src/QrReader.jsx
is like this:
import { onMount, onCleanup } from 'solid-js'
let videoEl = null
function QrReader() {
const barcodeDetector = new BarcodeDetector({ formats: ['qr_code'] })
const detectCode = () => {
if (videoEl?.srcObject) {
barcodeDetector.detect(videoEl).then(codes => {
if (codes.length === 0) return
for (const barcode of codes) {
alert(barcode.rawValue)
}
}).catch(err => {
console.error(err)
})
}
}
onMount(() => {
videoEl = document.querySelector('#video')
if (navigator.mediaDevices?.getUserMedia) {
const constraints = {
video: true,
audio: false
}
navigator.mediaDevices.getUserMedia(constraints).then(stream => videoEl.srcObject = stream)
}
})
const timer = setInterval(detectCode, 500)
onCleanup(() => clearInterval(timer))
return (
<video id="video" width="640" height="480" autoplay></video>
)
}
export default QrReader
Additional
Now, if we want to display recently scanned, then there are two files to be improved.
src/QrReader.jsx
src/App.jsx
First, in the src/App.jsx
file, add the detect prop used to get the value of the scanned QR, and then save the scanned deal into the state.
import styles from './App.module.css'
import QrReader from './QrReader'
import { createSignal, For } from 'solid-js'
function App() {
const [recentlyScanned, setRecentlyScanned] = createSignal([])
return (
<div class={styles.App}>
<h1>QR Code Scanner</h1>
<div class={styles.QrReaderWrapper}>
<QrReader onDetect={
(barcode) => {
if (barcode) {
setRecentlyScanned((recentlyScanned) => [...recentlyScanned, barcode.rawValue])
}
}}
/>
<div>
<h2>Recently Scanned</h2>
<ul>
<For each={recentlyScanned()}>
{(scanValue) => {
return (
<li>
{scanValue}
</li>
)
}}
</For>
</ul>
</div>
</div>
</div>
)
}
export default App
Add the code below in the src/App.module.css
file.
...
.QrReaderWrapper {
display: flex;
column-gap: 1rem;
}
Finally, change the code below in the src/QrReader.jsx
file.
...
function QrReader(props) {
...
const detectCode = () => {
if (videoEl?.srcObject) {
barcodeDetector.detect(videoEl).then(codes => {
if (codes.length === 0) return
for (const barcode of codes) {
props.onDetect(barcode)
}
}).catch(err => {
console.error(err)
})
}
}
...
Now you will see recently scanned in your browser.
Source code
You can find the source code for this tutorial on Github: https://github.com/janulius/simple-solid-qr-reader.
Reference
- https://www.solidjs.com/guides/getting-started
- https://nodejs.org/api/esm.html#node-imports
- https://developer.mozilla.org/en-US/docs/Web/API/BarcodeDetector
My name is Janulius. I am a Frontend Engineer at ralali.com. If this post is helpful, please recommend and share it! Thanks for your time.