QR / Barcode Scanner New in 1.0.8
Reads QR codes and barcodes into the screen — from the device's camera, from a USB or Bluetooth handheld scanner, or from a photo — and fires scan with what it read, so a scan can write a tag, look up a record or open a screen.
Reach for it when you need:
- Scanning a work-order or batch label at a line terminal and writing it to a tag
- A tablet on the floor that opens the right equipment screen from the code on the machine
- Checking a part number against a pattern before it is accepted
Component name: BarcodeScanner · Category: Input
In the palette: Reads QR codes and barcodes from the device camera, a USB/Bluetooth handheld scanner (keyboard wedge) or a photo. The scanned text becomes this widget's value ({{nodes.<scanner id>.props.value}}) and fires the scan event — wire scan → Set tag with value scan.text to write it to a tag. Decoding runs in a WebAssembly worker, never on the UI thread. The camera needs HTTPS or localhost; the handheld and image modes work over plain HTTP.
Properties
Any property can be bound to a tag, another component's property, or a query.
| Property | Type | Default | Description |
|---|---|---|---|
value | string | "" | The last ACCEPTED scan. Bind it by node id, e.g. {{nodes.<scanner id>.props.value}}. |
modes | object | {"camera":true,"hid":true,"image":true,"default":"camera"} | Which inputs the scanner offers, and which it shows first. |
↳ modes.camera | boolean | true | Offer the live camera mode. |
↳ modes.hid | boolean | true | Accept a USB/Bluetooth handheld scanner (it types like a keyboard). Listens in every mode while enabled, so a handheld works beside the camera. |
↳ modes.image | boolean | true | Offer decoding a picked or freshly taken photo. |
↳ modes.default | enum | camera | The mode shown first. Options: camera · hid · image. |
scanning | object | {"mode":"continuous","formats":"common","pattern":"","cooldo… (truncated) | What counts as a scan: continuous or single, accepted formats, an optional pattern, the duplicate cooldown and the per-second cap. |
↳ scanning.mode | enum | continuous | continuous keeps scanning; single stops after the first accepted code and shows "Scan again". Options: continuous · single. |
↳ scanning.formats | enum | common | Which symbologies are accepted. Fewer formats decode faster. A code outside the set fires scanRejected (reason format_not_allowed). Options: common · qr · matrix · linear · any. |
↳ scanning.pattern | string | "" | Optional regular expression a scan must match, e.g. ^PN-\d{6}$. A non-matching scan fires scanRejected (reason pattern_mismatch) instead of scan. |
↳ scanning.cooldownMs | number | 1500 | The same code read again within this many ms is ignored (no event) — a label held in front of the camera fires once. |
↳ scanning.maxPerSecond | number | 5 | Hard cap on accepted scans per second, so a scanner can never flood the tag-write path. |
feedback | object | {"beep":true,"vibrate":true,"showLastScan":true} | What the operator gets on a scan. |
↳ feedback.beep | boolean | true | Beep on a scan (a low tone on a rejected one). |
↳ feedback.vibrate | boolean | true | Vibrate on a scan (phones/tablets). |
↳ feedback.showLastScan | boolean | true | Show the last scanned text and its format under the scanner. |
camera | object | {"select":"back","nameMatch":"","showPicker":true,"showOverl… (truncated) | Which camera to use, the operator's camera picker, the aiming box and the decode rate. |
↳ camera.select | enum | back | Which camera to start: back (environment), front (user), or match = the first camera whose name contains nameMatch. The operator's own pick (camera dropdown) is remembered per browser and wins. Bindable. Options: back · front · match. |
↳ camera.nameMatch | string | "" | Part of the camera name to match, e.g. "Logitech" or "USB" (case-insensitive). |
↳ camera.showPicker | boolean | true | Let the operator choose among the device's cameras (and flip front/back). Turn off to lock the camera. |
↳ camera.showOverlay | boolean | true | Show the aiming box. Only the area inside it is decoded. |
↳ camera.scanRate | number | 10 | Target camera decodes per second. It backs off automatically on a slow device (down to 3/s). |
hid | object | {"scope":"global","terminator":"enter","minLength":4,"maxInt… (truncated) | USB/Bluetooth handheld scanner (keyboard wedge) detection. |
↳ hid.scope | enum | global | global: the handheld works whenever this view is open (not while the operator types in a text field). focused: only after clicking the scanner widget. Options: global · focused. |
↳ hid.terminator | enum | enter | The key the handheld sends after a code (Enter on most scanners). It is swallowed, so it never submits a form. Options: enter · tab · none. |
↳ hid.minLength | number | 4 | Shortest keystroke burst treated as a scan. |
↳ hid.maxInterKeyMs | number | 35 | Longest gap between keystrokes of one scan. Scanners type 5–20 ms apart, people 80+ ms; raise it only for a slow Bluetooth scanner. |
↳ hid.prefix | string | "" | Characters the scanner adds before the code, stripped from the value. |
↳ hid.suffix | string | "" | Characters the scanner adds after the code, stripped from the value. |
output | object | {"value":"","format":"","source":"","timestamp":0,"count":0,… (truncated) | Read-only runtime outputs — bind a leaf by node id, e.g. {{nodes.<scanner id>.props.output.format}}. |
↳ output.value | string | "" | Last accepted scan. |
↳ output.format | string | "" | Its symbology (qr_code, code_128, ean_13 …; unknown for a handheld scanner). |
↳ output.source | string | "" | camera, hid or image. |
↳ output.timestamp | number | 0 | When it was accepted, epoch ms. |
↳ output.count | number | 0 | Accepted scans since the view opened. |
↳ output.error | string | "" | The latest camera or decode error, or empty. |
↳ output.cameraState | string | idle | idle, starting, running, paused or error. |
↳ output.cameraId | string | "" | Active camera device id (this browser only). |
↳ output.cameraLabel | string | "" | Active camera name. |
style | style | {} | Custom CSS properties |
Events
Attach event actions to these in the Event Manager.
| Event | Label | Group | Payload |
|---|---|---|---|
click | Click | Mouse | The DOM event. |
dblclick | Double click | Mouse | The DOM event. |
contextmenu | Right click | Mouse | The DOM event. |
mouseenter | Mouse enter | Mouse | The DOM event. |
mouseleave | Mouse leave | Mouse | The DOM event. |
scan | Scan | Scanner | context.scan — { text, format, source: "camera"|"hid"|"image", timestamp (epoch-ms), count, cameraLabel }. In action fields: scan.text. |
scanRejected | Scan rejected | Scanner | context.scan — the same fields as scan plus reason: "format_not_allowed" | "pattern_mismatch". |
scanError | Scan error | Scanner | context.scan — { source, errorCode: "no_code_found"|"decode_failed", errorMessage }. |
cameraReady | Camera ready | Scanner | context.camera — { deviceId, label, facing: "front"|"back"|"unknown", width, height }. |
cameraChange | Camera changed | Scanner | context.camera — the newly active camera, same fields as cameraReady. |
cameraError | Camera error | Scanner | context.camera — { errorCode: "permission_denied"|"not_found"|"insecure_context"|"device_lost"|"in_use"|"unsupported", errorMessage, deviceId, label }. |
contextmenu fires your configured actions at runtime only — in LiveView and in preview. On the Designer canvas the right-click is captured to open the Event Manager, so testing it there will not run your actions. Test right-click in preview.
Notes
Wiring a scan to a tag
Handle Scan in the Event Manager with a Set tag action whose value is {{scan.text}} (the Event Manager offers it as Scanned text). The last accepted scan is also the widget's value, so another widget can bind to it by the scanner's node id. A script reads the scan as context.scan — { text, format, source, timestamp, count, cameraLabel }.
Three ways in
modes turns each input on or off and picks the one shown first:
- Camera — decodes the live picture inside the aiming box, about
camera.scanRate(10) times a second, backing off to 3 on a slow device. The camera needs HTTPS, or localhost; over plain HTTP the browser refuses it andcameraErrorfires withinsecure_context. The operator can switch cameras unlesscamera.showPickeris off, and their pick is remembered in that browser. The camera is released whenever the widget is hidden. - Handheld (
hid) — a USB or Bluetooth scanner types like a keyboard. The widget tells a scan from typing by its speed: a burst of at leasthid.minLength(4) characters with no gap overhid.maxInterKeyMs(35 ms) — scanners type 5–20 ms apart, people 80 ms or more. Withhid.scopeglobalit listens while the view is open, but never while the operator is typing in a text field;focusedlistens only after the widget is clicked. The terminator key the scanner sends (Enter on most) is swallowed, so it cannot submit a form. The handheld listens in every mode, beside the camera. - Image — decode a picked or freshly taken photo.
The handheld and image modes work over plain HTTP.
What counts as a scan
Every read passes one gate, set under scanning:
| Setting | Effect |
|---|---|
formats | common (default), qr, matrix, linear or any. Fewer decode faster. A code outside the set fires scanRejected with reason format_not_allowed. |
pattern | A regular expression the text must match, e.g. ^PN-\d{6}$. A miss fires scanRejected with reason pattern_mismatch. |
cooldownMs | The same code read again within 1,500 ms is ignored — no event — so a label held in front of the camera fires once. |
maxPerSecond | At most 5 accepted scans a second, so a scanner can never flood the tag writes. |
mode | continuous keeps scanning; single stops after the first accepted code and shows Scan again. |
feedback beeps (a low tone on a rejected scan), vibrates on a phone or tablet, and shows the last text and format under the scanner.
Events
scan, scanRejected and scanError (no code found, or a decode failure) carry scan; cameraReady, cameraChange and cameraError carry camera. A camera error names its cause — permission_denied, not_found, insecure_context, device_lost, in_use or unsupported — so a handler can tell the operator what to fix. output publishes the last scan, its format and source, a count, and the camera's state.
Decoding runs in a WebAssembly worker shipped with the product, never on the screen's main thread and never from the internet, so it works on an isolated network.