npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

modern-barcode-scanner

v1.0.3

Published

A high-performance barcode scanner React component with optimized detection, torch control, and camera switching

Downloads

289

Readme

GitHub Actions Workflow Status NPM Version NPM Downloads Socket Badge License: MIT


✨ Features

  • 🚀 High Performance: Web Worker-based scanning with optimized grayscale conversion.
  • 📱 Mobile Optimized: Automatic phone detection with appropriate camera selection.
  • 🔦 Torch Control: Built-in torch/flash support for low-light scanning.
  • 🔄 Camera Switching: Easy switching between front and back cameras.
  • 📷 Smart Camera Selection: Automatically selects the best rear camera (avoids ultra-wide/telephoto).
  • 🎯 Session Management: Prevents stale results with session-based tracking.
  • 🎨 Customizable UI: CSS-based styling with sensible defaults and CSS variables.
  • 📦 TypeScript Support: Full type definitions included out of the box.
  • 📳 Haptic Feedback: Standard Web Vibration API support for successful scans (Android/Desktop).
  • 🔊 Sound Feedback: Optional audio cues on successful scans.

🏷️ Supported Barcode Formats

  • 2D Codes: QR Code, PDF417
  • Retail Codes: EAN-13, EAN-8, UPC-A, UPC-E
  • Industrial/Standard Codes: Code 128, Code 39, Code 93, Codabar, ITF (Interleaved 2 of 5)
  • Books: ISBN-10, ISBN-13
  • DataBar (GS1)
  • And more! (Powered by ZBar)

📦 Installation

Choose your preferred package manager:

# npm
npm install modern-barcode-scanner

# yarn
yarn add modern-barcode-scanner

# pnpm
pnpm add modern-barcode-scanner

🚀 Quick Start

Here's a minimal example to get the scanner up and running in your React application:

import { useRef, useEffect } from "react";
import { BarcodeScanner, BarcodeScannerRef, ScanResult } from "modern-barcode-scanner";

// Import the stylesheet once, anywhere in your app. The CSS ships as a separate
// file (so you can override the design tokens), so it is NOT injected
// automatically — this import is required for the scanner to look right.
import "modern-barcode-scanner/styles.css";

function App() {
  const scannerRef = useRef<BarcodeScannerRef>(null);

  const handleScan = (result: ScanResult) => {
    console.log("📦 Barcode type:", result.typeName);
    console.log("📄 Barcode data:", result.scanData);

    // Scanner automatically stops after detection.
    // Call scannerRef.current?.start() to scan again!
  };

  const handleError = (error: Error) => {
    console.error("❌ Scanner error:", error.message);
  };

  useEffect(() => {
    // Start scanning when component mounts
    scannerRef.current?.start();
  }, []);

  return (
    <div style={{ width: "100vw", height: "100vh" }}>
      <BarcodeScanner
        ref={scannerRef}
        onScan={handleScan}
        onError={handleError}
        themeColor="#2563EB" // Customize the primary UI color!
      />
    </div>
  );
}

Zero bundler configuration

Under the hood, this library uses @undecaf/zbar-wasm for detection, running inside a Web Worker. Both the worker and its WebAssembly binary are inlined directly into the bundle — the worker as a Blob and the .wasm as embedded data.

This means you do not need any special bundler setup: no optimizeDeps exclusions, no copying a worker file out of node_modules, and no rules to serve .wasm assets. Just install, import, and go — it works the same across Vite, webpack, Next.js, and other bundlers.

The trade-off is a larger main bundle (the WASM binary is embedded), in exchange for it working out of the box in any consumer with no setup.


📖 API Reference

<BarcodeScanner /> Component

Props

| Prop | Type | Default | Description | | ------------------- | ------------------------------- | --------------- | ---------------------------------------------------------- | | onScan | (result: ScanResult) => void | Required | Callback fired when a barcode is detected. | | onError | (error: Error) => void | undefined | Callback fired when an error occurs. | | onStateChange | (state: ScannerState) => void | undefined | Callback fired when scanner state changes. | | themeColor | string | '#2563EB' | Primary theme color for UI elements and scan line. | | scanInterval | number | 100 | Time between scan attempts (in ms). | | enableVibration | boolean | true | Enable haptic feedback on scan (uses navigator.vibrate). | | vibrationDuration | number | 200 | Vibration duration (in ms). | | enableSound | boolean | false | Enable sound feedback on scan. | | initialFacingMode | 'user' \| 'environment' | 'environment' | Initial camera to use. | | showScanLine | boolean | true | Show scanning animation line. | | showCameraSwitch | boolean | true | Show camera switch button. | | showTorchButton | boolean | true | Show torch button (if supported). | | className | string | '' | Custom CSS class for the container. | | style | React.CSSProperties | undefined | Custom inline styles for the container. |

Ref Methods

Exposed via useImperativeHandle for direct control:

interface BarcodeScannerRef {
  start: () => Promise<void>; // Starts the camera and scanning
  stop: () => void; // Stops the camera and scanning
  switchCamera: () => Promise<void>; // Toggles between front and back camera
  toggleTorch: () => Promise<void>; // Toggles the torch/flash (if supported)
  getState: () => ScannerState; // Returns current state
}

TypeScript Types

interface ScanResult {
  typeName: string; // e.g., 'QRCODE', 'EAN13', 'CODE128'
  scanData: string; // The decoded barcode string
}

interface ScannerState {
  isScanning: boolean;
  facingMode: "user" | "environment";
  isTorchOn: boolean;
}

🛠️ Advanced Usage

Using the useScanner Hook

If you need complete control over the UI, you can use the internal hook directly:

import { useScanner } from "modern-barcode-scanner";

function CustomScanner() {
  const {
    scannerState,
    videoRef,
    canvasRef,
    handleScan,
    handleStopScan,
    handleSwitchCamera,
    handleToggleTorch,
  } = useScanner({
    onScan: (result) => console.log("Scanned:", result),
    onError: (error) => console.error("Error:", error),
    enableVibration: true,
  });

  return (
    <div>
      <video ref={videoRef} autoPlay muted playsInline />
      <canvas ref={canvasRef} hidden />

      <div className="controls">
        <button onClick={handleScan}>▶️ Start</button>
        <button onClick={handleStopScan}>⏹️ Stop</button>
        <button onClick={handleSwitchCamera}>🔄 Switch</button>
        {scannerState.isTorchOn ? "🔦 On" : "🔦 Off"}
      </div>
    </div>
  );
}

Helper Utilities

The library exports several useful utilities:

import { isPhone, getBestRearCamera, getMediaConstraints } from "modern-barcode-scanner";

// 📱 Check if device is a phone/tablet
const isMobile = isPhone();

// 📷 Get the optimal rear camera device ID (avoids ultra-wide lenses)
const cameraId = await getBestRearCamera();

// ⚙️ Get optimized media constraints based on facing mode
const constraints = await getMediaConstraints("environment");

🎨 Styling

The component uses CSS prefix mbs- (Modern Barcode Scanner) and supports native CSS variables for easy theming.

CSS Variables

You can easily override the primary color globally or via the themeColor prop:

:root {
  --mbs-primary: #ff0055; /* Changes scan line and active icon colors */
}

Overriding Classes

/* Custom container styling */
.mbs-container {
  border-radius: 1rem;
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}

/* Custom scan line */
.mbs-scan-line {
  height: 3px;
  box-shadow: 0 0 15px 3px var(--mbs-primary);
}

/* Custom control buttons */
.mbs-control-btn {
  background-color: rgba(255, 255, 255, 0.2);
  backdrop-filter: blur(4px);
}

🌐 Browser Support

| Browser / OS | Version | | --------------------- | --------- | | 🟢 Google Chrome | 79+ | | 🔵 Microsoft Edge | 79+ | | 🟠 Mozilla Firefox | 79+ | | 🧭 Safari (macOS) | 14.1+ | | 📱 Chrome for Android | Supported | | 🍎 Safari on iOS | 14.5+ |

⚠️ Note: Camera access requires a secure context (HTTPS) in production environments!


⚡ Performance Optimizations

This library is built for speed and reliability:

  1. Web Worker Processing: Barcode detection runs entirely off the main thread.
  2. Grayscale Conversion: Uses bitwise operations for incredibly fast image matrix processing.
  3. Frame Throttling: Configurable scanInterval perfectly balances detection speed with device battery/CPU usage.
  4. Session Management: Strictly prevents processing out-of-date or stale video frames.
  5. Smart Downscaling: Intelligently reduces image resolution for faster processing while maintaining read quality.
  6. Canvas Optimizations: Utilizes willReadFrequently and desynchronized rendering hints where supported.

🧑‍💻 Development

This project uses Vite+ (vp) as its unified toolchain — one tool for building, testing, linting, and formatting (it bundles Vite, Vitest, Oxlint, and Oxfmt). The npm scripts invoke the locally-installed vp binary, so npm install is all you need to get going.

# Install dependencies (includes Vite+)
npm install

# Start the live demo app at http://localhost:8080
npm run dev

Scripts

| Script | Description | | ------------------- | ----------------------------------------------------------------- | | npm run dev | Run the demo app with hot-module reload. | | npm run build | Build the library (ESM + CJS) and emit type declarations (tsc). | | npm run preview | Preview a production build of the demo. | | npm test | Run the test suite once (Vitest + jsdom + Testing Library). | | npm run lint | Lint the code with Oxlint. | | npm run format | Format the code with Oxfmt. | | npm run check | Format check + lint + type-check in a single command. | | npm run typecheck | Type-check the library and the demo with tsc. |

Demo

The demo/ app consumes the library the same way a published consumer does — importing it by package name (modern-barcode-scanner) and stylesheet (modern-barcode-scanner/styles.css) against its public API. Aliases in demo/vite.config.ts resolve those entry points to the local build during development, keeping the demo live-reloading while validating the real package surface.

Testing

Tests live next to the source as *.test.ts(x) and run under Vitest (via vp test) in a jsdom environment, with @testing-library/react for the component tests. Run the whole suite with npm test.


📝 License

MIT © Sumit Sahoo

Please refer to the LICENSE file for the full text.


🤝 Credits

  • Powerful barcode detection engine powered by ZBar WASM.