Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

35 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ“· Modern Barcode Scanner

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

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.

Releases

Packages

Contributors

Languages