@orbisk/vue-use-barcode-detection
@orbisk/vue-use-barcode-detection
Vue composable, drop-in scanner component, and polygon overlay for the Barcode Detection API. Vue 3 and Nuxt 4 ready.
📖 Full documentation & live demos →
What you get
useBarcodeDetector— reactive composable. Manages agetUserMediastream + RAF detection loop for<video>sources, or runs detection on demand for images / canvases / blobs.<UseBarcodeDetector />— drop-in scanner component.<video>+ camera + polygon overlay in one tag, with slots for custom UI.<BarcodeDetectorOverlay />— standalone SVG overlay drawing accepted (green) and rejected (red) barcode polygons over any source.@orbisk/nuxt-barcode-detection— Nuxt module: auto-imports the composable, registers the components globally, and ships an opt-in client polyfill plugin. Adds<UBarcodeInput />(input + scan modal) when@nuxt/uiis present.
Install
pnpm add @orbisk/vue-use-barcode-detection vue @vueuse/core
Requires Vue 3.5+ and @vueuse/core 14+ (peer dependencies).
Vue
The wrapper component is the fastest path — <video>, camera stream, and polygon overlay are wired up for you. start() must run from a user gesture (e.g. a click) so Safari/iOS will allow getUserMedia and video.play().
<script setup lang="ts">
import { UseBarcodeDetector } from '@orbisk/vue-use-barcode-detection'
</script>
<template>
<UseBarcodeDetector v-slot="{ start, stop, isActive, detected }">
<button @click="isActive ? stop() : start()">
{{ isActive ? 'Stop' : 'Start camera' }}
</button>
<ul>
<li v-for="b in detected" :key="b.rawValue">
<strong>{{ b.format }}</strong> — <code>{{ b.rawValue }}</code>
</li>
</ul>
</UseBarcodeDetector>
</template>
Reach for the composable when you need full control over the source element:
<script setup lang="ts">
import { useTemplateRef } from 'vue'
import { useBarcodeDetector } from '@orbisk/vue-use-barcode-detection'
const video = useTemplateRef<HTMLVideoElement>('video')
const { isSupported, detected, error, isActive, start, stop } = useBarcodeDetector(video)
</script>
<template>
<p v-if="!isSupported">BarcodeDetector is not available in this browser.</p>
<p v-else-if="error">{{ error.message }}</p>
<video ref="video" playsinline muted />
<button @click="isActive ? stop() : start()">
{{ isActive ? 'Stop' : 'Start camera' }}
</button>
</template>
The composable accepts any source BarcodeDetector#detect understands: HTMLVideoElement, HTMLImageElement, SVGImageElement, HTMLCanvasElement, ImageBitmap, OffscreenCanvas, VideoFrame, Blob, ImageData.
Key options
| Option | Type | Default | Description |
|---|---|---|---|
formats |
MaybeRefOrGetter<BarcodeFormat[] | undefined> |
all | Restrict detection to specific formats. Reactive — the underlying BarcodeDetector is rebuilt on change. |
immediate |
boolean |
false |
Auto-start once the source is available. Defaults to false because getUserMedia / video.play() need a user gesture in Safari/iOS. |
camera |
boolean | MediaTrackConstraints |
true |
For video sources. true calls getUserMedia with rear camera; pass constraints to override; false skips camera setup so you can supply your own stream. |
once |
MaybeRefOrGetter<boolean> |
false |
Stop after the first accepted detection. Pair with accept to stop only on matching barcodes. Call start() to re-arm. |
accept |
(b: DetectedBarcode) => boolean |
none | Predicate gating which detections count. Non-matching barcodes go to rejected instead of detected and don't trigger once. |
The composable returns isSupported, supportedFormats, detected, rejected, error, isActive, detect(), start(), stop(). See the useBarcodeDetector reference for the full API, reactive options, the headless mode, and the <BarcodeDetectorOverlay /> props.
Scan once / filter scans
// Stop the camera on the first QR code
useBarcodeDetector(video, {
once: true,
accept: (b) => b.format === 'qr_code',
})
accept filters detected itself — non-matching barcodes appear in rejected instead, never trigger once, and (in <UseBarcodeDetector />) are drawn in red so users see why a scan was ignored.
Nuxt
export default defineNuxtConfig({
modules: ['@orbisk/nuxt-barcode-detection'],
})
useBarcodeDetector becomes an auto-import; <UseBarcodeDetector /> and <BarcodeDetectorOverlay /> are registered globally. When @nuxt/ui is also installed, the module additionally registers <UBarcodeInput /> — a UInput paired with a scan button that opens a live-camera modal.
<template>
<UseBarcodeDetector v-slot="{ detected }">
<pre>{{ detected }}</pre>
</UseBarcodeDetector>
</template>
See the Nuxt module docs and the Nuxt UI integration for module options, <UBarcodeInput /> props, and the install wizard.
Browser support & polyfill
The Barcode Detection API is part of the Shape Detection family — natively wired up on Chromium for ChromeOS, macOS, and Android. Desktop Linux Chromium, Firefox, and Safari ship the engine without the platform-side decoder.
For full coverage, drop in the barcode-detector polyfill — a ZXing-based wasm fallback that only patches globalThis.BarcodeDetector when missing.
pnpm add barcode-detector
if (typeof window !== 'undefined' && !('BarcodeDetector' in window)) {
await import('barcode-detector/polyfill')
}
In Nuxt, set barcodeDetection.polyfill: true (the install wizard offers this on first run) and the module ships a client plugin that loads the polyfill on demand. Both the composable and the wrapper component expose isSupported so you can render a fallback UI when neither native nor polyfill is available.
See Compatibility & polyfill for the full browser support table and Nuxt wiring.
Develop
This project uses Vite+ (vp) — one toolchain that bundles Vite, Vitest, Oxlint, and Oxfmt. Everything is configured in vite.config.ts.
pnpm install
pnpm dev:prepare # generate the Nuxt module's dev stub (required before docs:dev / typecheck)
pnpm dev # boot the playground (Vite dev server)
pnpm test # vp test in watch mode
pnpm test:run # single-shot tests for CI
pnpm check # format + lint + typecheck (vp check)
pnpm fmt # format with oxfmt
pnpm lint:fix # autofix with oxlint
pnpm build # produce the library bundle
pnpm docs:dev # boot the Nuxt Content docs site (also covers SSR)
Add a new composable
- Create
src/<useFoo>/index.tsexporting your function. - Add a co-located
<useFoo>/index.test.tswith Vitest tests. - Add a
<useFoo>/demo.vueso it renders in the playground. - Re-export from
src/index.ts. - Add a docs page at
docs/content/functions/<use-foo>.md. The sidebar picks it up automatically fromqueryCollection('docs').
Related Packages
Nuxt module for @orbisk/vue-use-barcode-detection (auto-imports, components, pol...
ZPL-native barcode and label image components for Vue 3, powered by ZPL.AI.
Version History
| Version | Released | Vue | License |
|---|---|---|---|
| 0.5.0 | ^3.5.0 | MIT | |
| 0.4.0 | ^3.5.0 | MIT | |
| 0.3.2 | ^3.5.0 | MIT | |
| 0.3.1 | ^3.5.0 | MIT | |
| 0.3.0 | ^3.5.0 | MIT | |
| 0.2.0 | ^3.5.0 | MIT | |
| 0.1.4 | ^3.5.0 | MIT | |
| 0.1.0 | ^3.5.0 | MIT |