V3 barcodes
The fliplet-barcode package does two things in a V3 app, both the same on web and native: it scans QR codes and barcodes with Fliplet.Barcode.attachScanner(), and it generates QR code and barcode images with Fliplet.Barcode.encode().
Scanning uses attachScanner() — a UI-less scanner you drive into a container element inside your own screen. It runs everywhere a V3 app runs (slug-hosted web, the Studio preview, and the native shell). You build the scanning UI yourself, the same way you build a login screen on top of Fliplet.Session; the API owns only the camera and the decoder.
This guide covers the recommended embedded-scanner pattern, a full worked example, the controller and options, camera permissions, and generating barcode images.
Prerequisites
Add the fliplet-barcode package to the screen, then load it before use:
await Fliplet.require.lazy.chain('fliplet-barcode');
Once the package is loaded, Fliplet.Barcode exposes two methods, both of which work the same on web and native: attachScanner() (scan, documented below) and encode() (generate a QR code or barcode image, documented under Generating barcodes).
The recommended pattern: attachScanner()
attachScanner() has no built-in UI. You place and style a container element; attachScanner() runs the camera and decoder into it and calls you back on each successful decode. Because there is no platform-specific overlay, the same code works on web and native.
// Your screen owns this element and its styling:
// <div id="reader" style="width: 100%; max-width: 320px; aspect-ratio: 1;"></div>
const scanner = Fliplet.Barcode.attachScanner(document.getElementById('reader'), {
onScan(result) {
// result.text — the decoded value, e.g. "https://example.com" or "5012345678900"
// result.format — the symbology, e.g. "QR_CODE", "CODE_128", "EAN_13"
scanner.stop(); // one-shot: stop after the first hit (omit to keep scanning)
showResult(result.text);
},
onError(error) {
// Fatal start error: camera permission denied, no camera, or library load failure.
showMessage('Could not start the scanner. Check camera permissions and try again.');
}
});
// Stop the camera when the user leaves the screen or closes your scanner UI:
scanner.stop();
Worked example: tap a button to scan
A typical scanning screen keeps the viewfinder hidden until the user asks for it, scans once, then shows the result. This is the whole flow in vanilla JS:
<button id="scan-btn">Scan a barcode</button>
<div id="reader" hidden style="width: 100%; max-width: 320px; aspect-ratio: 1; margin-top: 16px;"></div>
<p id="result"></p>
await Fliplet.require.lazy.chain('fliplet-barcode');
const btn = document.getElementById('scan-btn');
const reader = document.getElementById('reader');
const resultEl = document.getElementById('result');
let scanner = null;
btn.addEventListener('click', function () {
reader.hidden = false;
scanner = Fliplet.Barcode.attachScanner(reader, {
onScan(result) {
resultEl.textContent = `${result.format}: ${result.text}`;
scanner.stop();
reader.hidden = true;
},
onError() {
resultEl.textContent = 'Camera unavailable — check permissions.';
reader.hidden = true;
}
});
});
Vue component
In a V3 Vue screen, start the scanner from a button handler and always stop it on unmount so the camera is released:
// Scanner.vue (runtime template — V3 single-file components run without a build step)
export default {
data() {
return { value: '', scanner: null };
},
methods: {
async start() {
await Fliplet.require.lazy.chain('fliplet-barcode');
this.scanner = Fliplet.Barcode.attachScanner(this.$refs.reader, {
onScan: (result) => {
this.value = result.text;
this.scanner.stop();
},
onError: () => { this.value = 'Camera unavailable.'; }
});
}
},
beforeUnmount() {
if (this.scanner) {
this.scanner.stop();
}
},
template: `
<div>
<button @click="start">Scan</button>
<div ref="reader" style="width: 100%; max-width: 320px; aspect-ratio: 1;"></div>
<p v-if="value"></p>
</div>
`
};
Controller and options
attachScanner(element, options) returns a controller and accepts:
-
element (HTMLElement String) — the container to render the camera into (an element or its id). You own its placement and styling;attachScanner()neither creates nor removes it. - options.onScan (Function) — called on every successful decode with
{ text, format }. Callcontroller.stop()inside it for one-shot scanning. - options.onError (Function) — called on a fatal start error (permission denied, no camera, or library load failure). Per-frame decode misses are not errors and are ignored.
- options.fps (Number) — decode attempts per second. Default
10. -
options.qrbox (Object Function) — scan-box size. Defaults to a centered square at 70% of the smaller edge.
The controller is { stop() }. stop() ends the camera, tears down the decoder (your element stays in the DOM), and returns a Promise.
Camera permissions
- Web — the browser prompts for camera access when scanning starts, and
getUserMediarequires a secure context (HTTPS). In the Studio preview the app runs in an iframe that already delegatescamera; a published slug is served over HTTPS. - Native — the OS prompts on first use.
Handle a denied permission in onError — show the user how to re-enable the camera rather than leaving an empty viewfinder.
Generating barcodes
To render a QR code or barcode image, use Fliplet.Barcode.encode(). It works on web and native, returns the image as a Base64 string, and defaults to a QR code unless you pass a different format. You place the returned image in your own UI — the same “you own the UI” model as attachScanner() — for example into an <img> src, or save it with Fliplet.Media.
Fliplet.Barcode.encode()
Encode text into a QR code or barcode and resolve with the image as a Base64 string.
await Fliplet.require.lazy.chain('fliplet-barcode');
// QR code (default)
Fliplet.Barcode.encode('https://example.com').then(function (data) {
document.getElementById('qr').src = data; // <img id="qr">
});
// Barcode with options
Fliplet.Barcode.encode('5012345678900', { format: 'ean13' }).then(function (data) {
document.getElementById('code').src = data;
});
- text (String) — the value to encode.
- options (Object)
- format (String) —
qr(default), orbarcode(encodes ascode128), or a specific symbology:code39,code128,code128A,code128B,code128C,ean13,ean8,ean5,ean2,upc,upce,itf14,itf,msi,msi10,msi11,msi1010,msi1110,pharmacode,codabar,genericbarcode. - color (String) — foreground color, keyword (
green) or hex (#00ff00). Default#000000. - background (String) — background color, keyword or hex. Default
#ffffff. - width (Number) — QR code only. Width of the QR image. Default
600. (Barcode width is driven by the text length andlineWidth.) - height (Number) — height of the image. Default
600for QR,150for barcode. - lineWidth (Number) — barcode only. Width of a single bar; larger values produce a wider image. Default
2.
- format (String) —
Tip: QR codes are always 1:1, so they scale cleanly. Prefer a QR code unless a linear barcode is specifically required; for barcodes, tune
heightandlineWidthto the length of the encoded text.encode()returns the raw image and renders no UI of its own — display it however your screen needs.
Patterns — DO and DON’T
DO
- Build your own scanning UI (button, viewfinder container, result area) and drive
attachScanner()into it. - Call
controller.stop()after the first scan for one-shot flows, and on screen teardown/unmount to release the camera. - Handle
onErrorwith a user-facing message about camera permissions. - Give the container an explicit size — the camera fills it.
DON’T
- Don’t leave the scanner running after navigation — a live camera drains battery and blocks other capture.
- Don’t add a separate “scanner” package or a custom camera/getUserMedia stack —
attachScanner()is the supported cross-platform scanner.
Related
- V3 routing — base-path and navigation patterns for the screen that hosts your scanner.