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

react-native-simple-scanner

v0.3.4

Published

A lightweight and simple barcode/QR code scanner for React Native

Readme

react-native-simple-scanner

npm version npm downloads License: MIT PRs Welcome

A lightweight and simple barcode/QR code scanner for React Native with Fabric View support.

Features

  • 🚀 Lightweight: Bundle size <2MB
  • 📱 iOS Support: iOS 14+ (Android coming in Phase 2)
  • 🔧 Simple API: Easy to use, minimal setup
  • 🎯 TypeScript: Full TypeScript support with strict mode
  • Fabric View: React Native new architecture support
  • 📸 Multiple Formats: QR Code, EAN-13, EAN-8, CODE-128, UPC-A, UPC-E, Code-39

Installation

pnpm add react-native-simple-scanner
# or
npm install react-native-simple-scanner
# or
yarn add react-native-simple-scanner

iOS Setup

  1. Install pods:
cd ios && pod install && cd ..
  1. Add camera permission to Info.plist:
<key>NSCameraUsageDescription</key>
<string>This app needs camera access to scan barcodes</string>

Usage

Basic Example

import React, { useState } from 'react';
import { View, Text, Alert } from 'react-native';
import {
  BarcodeScannerView,
  type BarcodeResult,
} from 'react-native-simple-scanner';

export default function App() {
  const handleBarcodeScanned = (result: BarcodeResult) => {
    Alert.alert(
      'Barcode Scanned',
      `Type: ${result.type}\nData: ${result.data}`
    );
  };

  return (
    <View style={{ flex: 1 }}>
      <BarcodeScannerView
        barcodeTypes={['qr', 'ean13']}
        onBarcodeScanned={handleBarcodeScanned}
        style={{ flex: 1 }}
      />
    </View>
  );
}

With Flash Control

import React, { useState } from 'react';
import { TouchableOpacity, Text } from 'react-native';
import { BarcodeScannerView } from 'react-native-simple-scanner';

export default function App() {
  const [flashOn, setFlashOn] = useState(false);

  return (
    <>
      <BarcodeScannerView
        barcodeTypes={['qr']}
        onBarcodeScanned={(result) => console.log(result)}
        flashEnabled={flashOn}
        style={{ flex: 1 }}
      />
      <TouchableOpacity onPress={() => setFlashOn(!flashOn)}>
        <Text>Toggle Flash</Text>
      </TouchableOpacity>
    </>
  );
}

Error Handling

import { Linking, Alert } from 'react-native';
import {
  BarcodeScannerView,
  ScannerError,
  ScannerErrorCode,
} from 'react-native-simple-scanner';

<BarcodeScannerView
  barcodeTypes={['qr']}
  onBarcodeScanned={(result) => console.log(result)}
  onError={(error: ScannerError) => {
    if (error.code === ScannerErrorCode.PERMISSION_DENIED) {
      Alert.alert(
        'Camera Permission Required',
        'Please enable camera access in Settings',
        [
          { text: 'Cancel', style: 'cancel' },
          { text: 'Open Settings', onPress: () => Linking.openSettings() },
        ]
      );
    } else {
      Alert.alert('Error', error.message);
    }
  }}
/>;

With Scan Interval Control

import { BarcodeScannerView } from 'react-native-simple-scanner';

<BarcodeScannerView
  barcodeTypes={['qr']}
  onBarcodeScanned={(result) => console.log(result)}
  scanInterval={2000} // Prevent duplicate scans for 2 seconds
  style={{ flex: 1 }}
/>;

With Camera Ready Callback

import { BarcodeScannerView } from 'react-native-simple-scanner';

<BarcodeScannerView
  barcodeTypes={['qr']}
  onBarcodeScanned={(result) => console.log(result)}
  onCameraReady={() => {
    console.log('Camera is ready!');
  }}
  style={{ flex: 1 }}
/>;

With Camera Permission Helpers

import React, { useEffect, useState } from 'react';
import { View, Text, ActivityIndicator } from 'react-native';
import {
  BarcodeScannerView,
  checkCameraPermission,
  requestCameraPermission,
  type PermissionStatus,
} from 'react-native-simple-scanner';

export default function App() {
  const [permissionStatus, setPermissionStatus] =
    useState<PermissionStatus>('not-determined');
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    const checkPermission = async () => {
      const status = await checkCameraPermission();
      setPermissionStatus(status);
      setLoading(false);

      if (status === 'not-determined') {
        const granted = await requestCameraPermission();
        setPermissionStatus(granted ? 'granted' : 'denied');
      }
    };

    checkPermission();
  }, []);

  if (loading) {
    return <ActivityIndicator />;
  }

  if (permissionStatus !== 'granted') {
    return <Text>Camera permission required</Text>;
  }

  return (
    <BarcodeScannerView
      barcodeTypes={['qr']}
      onBarcodeScanned={(result) => console.log(result)}
      style={{ flex: 1 }}
    />
  );
}

With Camera Status Change

import React, { useState } from 'react';
import { View, Text, ActivityIndicator } from 'react-native';
import {
  BarcodeScannerView,
  type CameraStatus,
} from 'react-native-simple-scanner';

export default function App() {
  const [cameraStatus, setCameraStatus] =
    useState<CameraStatus>('initializing');

  return (
    <View style={{ flex: 1 }}>
      {cameraStatus === 'initializing' && (
        <View
          style={{
            position: 'absolute',
            top: 0,
            left: 0,
            right: 0,
            bottom: 0,
            justifyContent: 'center',
            alignItems: 'center',
          }}
        >
          <ActivityIndicator />
          <Text>Preparing camera...</Text>
        </View>
      )}

      {cameraStatus === 'permission-required' && (
        <View
          style={{
            position: 'absolute',
            top: 0,
            left: 0,
            right: 0,
            bottom: 0,
            justifyContent: 'center',
            alignItems: 'center',
          }}
        >
          <Text>Camera permission required</Text>
        </View>
      )}

      <BarcodeScannerView
        barcodeTypes={['qr']}
        onBarcodeScanned={(result) => console.log(result)}
        onCameraStatusChange={setCameraStatus}
        style={{ flex: 1 }}
      />
    </View>
  );
}

With Scanning Pause/Resume

import React, { useState } from 'react';
import { View, Button, Alert } from 'react-native';
import { BarcodeScannerView } from 'react-native-simple-scanner';

export default function App() {
  const [isScanning, setIsScanning] = useState(true);

  const handleBarcodeScanned = (result) => {
    setIsScanning(false); // Pause scanning

    Alert.alert('Scanned', result.data, [
      { text: 'Scan Again', onPress: () => setIsScanning(true) },
    ]);
  };

  return (
    <View style={{ flex: 1 }}>
      <BarcodeScannerView
        barcodeTypes={['qr']}
        onBarcodeScanned={handleBarcodeScanned}
        isScanning={isScanning}
        style={{ flex: 1 }}
      />
    </View>
  );
}

With Bounding Box Overlay

import React, { useState } from 'react';
import { View, StyleSheet } from 'react-native';
import {
  BarcodeScannerView,
  type BarcodeResult,
} from 'react-native-simple-scanner';

export default function App() {
  const [highlightBox, setHighlightBox] = useState<
    BarcodeResult['bounds'] | null
  >(null);

  const handleBarcodeScanned = (result: BarcodeResult) => {
    if (result.bounds) {
      setHighlightBox(result.bounds);

      // Clear highlight after animation
      setTimeout(() => setHighlightBox(null), 500);
    }

    console.log('Scanned:', result.data);
  };

  return (
    <View style={{ flex: 1 }}>
      <BarcodeScannerView
        barcodeTypes={['qr']}
        onBarcodeScanned={handleBarcodeScanned}
        style={{ flex: 1 }}
      />

      {highlightBox && (
        <View
          style={[
            styles.highlight,
            {
              left: highlightBox.x,
              top: highlightBox.y,
              width: highlightBox.width,
              height: highlightBox.height,
            },
          ]}
        />
      )}
    </View>
  );
}

const styles = StyleSheet.create({
  highlight: {
    position: 'absolute',
    borderWidth: 2,
    borderColor: '#00FF00',
    backgroundColor: 'transparent',
  },
});

API Reference

BarcodeScannerView

Main component for scanning barcodes.

Props

| Prop | Type | Default | Description | | ---------------------- | --------------------------------- | ------------ | ---------------------------------------------------------------------------- | | barcodeTypes | BarcodeType[] | ['qr'] | Array of barcode types to detect | | onBarcodeScanned | (result: BarcodeResult) => void | Required | Callback fired when a barcode is scanned | | flashEnabled | boolean | false | Enable/disable flashlight | | onError | (error: ScannerError) => void | - | Callback fired when an error occurs | | scanInterval | number | 1000 | Minimum interval between scanning the same barcode (ms). Set to 0 to disable | | onCameraReady | () => void | - | Callback fired when camera is ready | | onCameraStatusChange | (status: CameraStatus) => void | - | Callback fired when camera status changes | | isScanning | boolean | true | Whether barcode detection is active | | style | ViewStyle | - | Component style | | testID | string | - | Test ID for testing purposes |

Types

BarcodeType

type BarcodeType =
  | 'qr'
  | 'ean13'
  | 'ean8'
  | 'code128'
  | 'upc-a'
  | 'upc-e'
  | 'code-39';

BarcodeResult

interface BarcodeResult {
  type: BarcodeType;
  data: string;
  timestamp: number;
  bounds?: {
    x: number;
    y: number;
    width: number;
    height: number;
  };
}

ScannerError

class ScannerError extends Error {
  code: ScannerErrorCode;
  message: string;
}

ScannerErrorCode

enum ScannerErrorCode {
  CAMERA_UNAVAILABLE = 'CAMERA_UNAVAILABLE',
  PERMISSION_DENIED = 'PERMISSION_DENIED',
  CONFIGURATION_FAILED = 'CONFIGURATION_FAILED',
  UNKNOWN = 'UNKNOWN',
}

PermissionStatus

type PermissionStatus = 'granted' | 'denied' | 'not-determined';

CameraStatus

type CameraStatus = 'initializing' | 'ready' | 'error' | 'permission-required';

Helper Functions

checkCameraPermission()

Check current camera permission status without prompting the user.

import { checkCameraPermission } from 'react-native-simple-scanner';

const status = await checkCameraPermission();
// Returns: 'granted' | 'denied' | 'not-determined'

requestCameraPermission()

Request camera permission from the user.

import { requestCameraPermission } from 'react-native-simple-scanner';

const granted = await requestCameraPermission();
// Returns: boolean (true if granted, false otherwise)

Testing

Use the provided Jest mock module for testing:

import { setupMocks, simulateScan, resetMocks } from 'react-native-simple-scanner/mocks';

// In jest.setup.js
setupMocks();

// In test file
describe('ScannerScreen', () => {
  beforeEach(() => {
    resetMocks();
  });

  it('handles barcode scan', () => {
    render(<ScannerScreen />);

    simulateScan({
      type: 'ean13',
      data: '9784873117324',
      timestamp: Date.now(),
    });

    expect(screen.getByText('ISBN detected!')).toBeTruthy();
  });
});

Supported Barcode Types

  • QR Code (qr): QR codes
  • EAN-13 (ean13): European Article Number (13 digits)
  • EAN-8 (ean8): European Article Number (8 digits)
  • CODE-128 (code128): Code 128 barcodes
  • UPC-A (upc-a): Universal Product Code Version A (12 digits)
  • UPC-E (upc-e): Universal Product Code Version E (6 digits)
  • Code-39 (code-39): Code 39 barcodes

Requirements

  • React Native >= 0.72.0
  • iOS >= 14.0
  • TypeScript >= 4.8 (recommended)

Troubleshooting

Camera Permission Issues

Make sure you have added NSCameraUsageDescription to your Info.plist:

<key>NSCameraUsageDescription</key>
<string>This app needs camera access to scan barcodes</string>

Camera Not Starting

  • Ensure you're testing on a real device (simulator doesn't support camera)
  • Check that camera permissions are granted in Settings
  • Verify that Info.plist contains the camera usage description

Build Errors

If you encounter build errors:

  1. Clean build folders:
pnpm clean
  1. Reinstall pods:
cd ios && pod install && cd ..
  1. Rebuild the project

Contributing

See CONTRIBUTING.md for details.

Contributors

This project follows the all-contributors specification. Contributions of any kind welcome!

License

MIT

Roadmap

  • [ ] Android support (Phase 2)
  • [ ] Additional barcode formats
  • [ ] Custom overlay UI options
  • [ ] Zoom control