BarcodeScanner Example—Self-Service Kiosk (Legacy)
Here’s a complete example of a Lightning web component with BarcodeScanner that could serve as a self-service kiosk.
We recommend using the modern scan() and dismiss() API functions in your LWC scanning code to streamline your development experience. The legacy API functions beginCapture(), resumeCapture(), and endCapture() are still available, but will be retired in a future release. See Understand BarcodeScanner Modern and Legacy APIs for additional details.
The HTML template provides the bare minimum for a scanning user interface. There’s an element to display the results of the scans, a bit of static help text, and a button to start scanning.
1
2<template>
3 <div class="slds-text-align_center">
4 <span class="slds-text-heading_large">BarcodeScanner: Multi-Scan</span>
5 </div>
6
7
8 <template lwc:if="{scannedBarcodes}">
9 <div
10 class="slds-var-m-vertical_large slds-var-p-vertical_medium
11 slds-text-align_center slds-border_top slds-border_bottom"
12 >
13 Scanned barcode values are:
14 <span class="slds-text-heading_small">{scannedBarcodesAsString}</span>
15 </div>
16 </template>
17
18
19 <div class="slds-text-align_center slds-text-color_weak slds-m-vertical_large">
20 Click <strong>Start a Scanning Session</strong> to open a barcode scanner camera view. Position
21 a barcode in the scanner view to scan it.
22
23 <p>Continue scanning items. Click ✖ when there are no more items to scan.</p>
24 </div>
25
26
27 <div class="slds-align_absolute-center slds-m-vertical_large">
28 <lightning-button
29 variant="brand"
30 class="slds-var-m-left_x-small"
31 icon-name="utility:scan"
32 label="Start a Scanning Session"
33 title="Start scanning barcodes, until there are no more barcodes to scan"
34 onclick="{beginScanning}"
35 ></lightning-button>
36 </div>
37
38
39 <div data-id="BarcodeScannerCustomUI" style="display: none;">
40 <div>
41 <h1 align="right">
42 <a style="text-decoration: none;" href="nimbusbarcodescanner://dismiss">✖</a>
43 </h1>
44 <h2 align="center">Welcome, let's get you verified!</h2>
45 <h3 align="center">
46 Point the front side of your Health Card<br />at the camera on this device.
47 </h3>
48 </div>
49 </div>
50</template>
This example borrows heavily from the code sample in BarcodeScanner Example—Continuous Scanning (Legacy). The differences in this example provide all the basic elements needed for a self-service kiosk use case. It uses the front-facing camera for scanning, employs a continuous scanning lifecycle to minimize the need for user interaction, and even defines and uses a custom UI.
1// barcodeScannerKiosk.js
2import { LightningElement, track } from "lwc";
3import { ShowToastEvent } from "lightning/platformShowToastEvent";
4import { getBarcodeScanner } from "lightning/mobileCapabilities";
5
6export default class NimbusPluginBarcodeScannerCustomUI extends LightningElement {
7 sessionScanner;
8 @track scannedBarcodes;
9
10 connectedCallback() {
11 this.sessionScanner = getBarcodeScanner();
12 }
13
14 beginScanning() {
15 // Reset scannedBarcodes before starting new scanning session
16 this.scannedBarcodes = [];
17
18 // Make sure BarcodeScanner is available before trying to use it
19 if (this.sessionScanner != null && this.sessionScanner.isAvailable()) {
20 let elem = this.template.querySelector("div[data-id=BarcodeScannerCustomUI]");
21 let backgroundViewHTML =
22 '<header><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"></header>';
23 backgroundViewHTML += `<html><body>${elem.innerHTML}</body></html>`;
24
25 // Specify the size of the scanner camera view, use of the front-facing camera, and pull in the custom UI defined above
26 const scanningOptions = {
27 barcodeTypes: [this.sessionScanner.barcodeTypes.QR],
28 scannerSize: "XLARGE",
29 cameraFacing: "FRONT",
30 showSuccessCheckMark: true,
31 presentWithAnimation: false,
32 backgroundViewHTML: backgroundViewHTML,
33 };
34
35 this.sessionScanner
36 .beginCapture(scanningOptions)
37 .then((scannedBarcode) => {
38 this.processScannedBarcode(scannedBarcode);
39 this.continueScanning();
40 })
41 .catch((error) => {
42 this.processError(error);
43 this.sessionScanner.endCapture();
44 });
45 } else {
46 console.log("BarcodeScanner unavailable. Non-mobile device?");
47 }
48 }
49
50 async continueScanning() {
51 // Pretend to do some work; see timing note below.
52 await new Promise((resolve) => setTimeout(resolve, 1000));
53
54 this.sessionScanner
55 .resumeCapture()
56 .then((scannedBarcode) => {
57 this.processScannedBarcode(scannedBarcode);
58 this.continueScanning();
59 })
60 .catch((error) => {
61 this.processError(error);
62 this.sessionScanner.endCapture();
63 });
64 }
65
66 processScannedBarcode(barcode) {
67 // Do something with the barcode scan value:
68 // - look up a record
69 // - create or update a record
70 // - parse data and put values into a form
71 // - and so on; this is YOUR code
72 console.log(JSON.stringify(barcode));
73 this.scannedBarcodes.push(barcode);
74 }
75
76 processError(error) {
77 // Check to see if user ended scanning
78 if (error.code == "USER_DISMISSED") {
79 console.log("User terminated scanning session via Cancel.");
80 } else {
81 console.error(error);
82 }
83 }
84
85 get scannedBarcodesAsString() {
86 return this.scannedBarcodes
87 .map((barcodeResult) => {
88 return barcodeResult.value;
89 })
90 .join("\n\n");
91 }
92}
This example doesn’t process a scanned barcode in any meaningful way. As a result, the processScannedBarcode() function executes quickly—too quickly. It can trigger a timing issue that causes the example to fail. To avoid the issue, we’ve inserted a one-second delay before starting the next scan. Real-world barcode processing typically takes long enough to avoid the issue. In that case, you can remove the line with the delay and the async keyword preceding the continueScanning() function.
See Scan Multiple Barcodes (Legacy) for an explanation of how beginScanning() and continueScanning() work together to create the continuous scanning cycle.
See Also