Compatibility & polyfill

Browser support for the Barcode Detection API and how to ship a polyfill where it's missing.

Compatibility & polyfill

The Barcode Detection API is part of the Shape Detection family — implemented by some browsers, gated behind a flag in others, and still missing in a few. The composable surfaces this through isSupported, and the wrapper component renders a fallback UI when the API isn't there.

Browser support

The table below is generated from MDN's browser-compat-data (the same dataset behind the MDN compatibility tables) and refreshes on every docs build.

Desktop

Chrome88+ (partial)
  • Supported on ChromeOS and macOS only.
  • Before Chrome 113, on macOS Ventura (13) and above, this interface silently failed. See bug 40245611.
Edge83+ (partial)
  • Supported on macOS only.
  • Before Chrome 113, on macOS Ventura (13) and above, this interface silently failed. See bug 40245611.
FirefoxNo
Safari17+ (flag)
  • Behind preference: Shape Detection API
Opera69+ (partial)
  • Supported on macOS only.
  • Before Chrome 113, on macOS Ventura (13) and above, this interface silently failed. See bug 40245611.

Mobile

Chrome Android83+
Firefox AndroidNo
Safari iOS17+ (flag)
  • Behind preference: Shape Detection API
Samsung Internet83+
Opera Android69+ (partial)
  • Supported on macOS only.
  • Before Chrome 113, on macOS Ventura (13) and above, this interface silently failed. See bug 40245611.

Source: mdn/browser-compat-data · MDN compatibility table

Native support varies by platform, not just by browser. On Chromium-based browsers, the API is typically only wired up on ChromeOS, macOS, and Android — desktop Linux ships the engine without the platform-side decoder. The barcode-detector polyfill below lifts that limitation.

Polyfill

barcode-detector is a drop-in polyfill that uses ZXing compiled to WebAssembly under the hood. The ./polyfill entry only patches globalThis.BarcodeDetector when the API is missing, so native implementations keep winning where they exist.

pnpm add barcode-detector

Vue

Import the polyfill once at app startup, before mounting:

main.ts
import { createApp } from 'vue'
import App from './App.vue'

if (typeof window !== 'undefined' && !('BarcodeDetector' in window)) {
  await import('barcode-detector/polyfill')
}

createApp(App).mount('#app')

The dynamic import() keeps the wasm bundle out of the main chunk for browsers that already have native support.

Nuxt

Use a client plugin so SSR is unaffected:

plugins/barcode-detector.client.ts
export default defineNuxtPlugin(async () => {
  if ('BarcodeDetector' in window) return
  await import('barcode-detector/polyfill')
})

That's how this docs site itself runs — every demo on the site works in Firefox, Safari, and desktop Linux Chromium thanks to the polyfill.

Detecting support at runtime

Both the composable and the wrapper component expose isSupported. Use it to render a fallback UI (file picker, manual entry, etc.) when neither native nor the polyfill is available:

<script setup lang="ts">
import { useBarcodeDetector } from '@orbisk/vue-use-barcode-detection'

const { isSupported } = useBarcodeDetector(null, { immediate: false })
</script>

<template>
  <p v-if="!isSupported">
    Barcode scanning isn't available in this browser.
    <a href="...">Type the code manually</a> instead.
  </p>
</template>

isSupported is gated behind useMounted() in the wrapper component, so it's always false on the server — no hydration mismatches.

Copyright © 2026