npm package: @ismnoiet/react-native-qrcode-scanner
Description: Native iOS QR code scanner for React Native with SwiftUI Dynamic Island animation, fully configurable scan line, border, and camera viewport.
Author: ismnoiet
Latest version: 1.0.0

# @ismnoiet/react-native-qrcode-scanner

> Native iOS QR code scanner that bursts out of the **Dynamic Island** — powered by SwiftUI, zero external dependencies.

A hardware-accelerated QR code scanner that animates out of the Dynamic Island pill (or the top of the screen on older devices). Drop in one component, pass a boolean, and you're scanning. Every visual detail is tunable via React Native props.


## Demo
<p align="center">
  <img src="./qr-scanner-demo.gif" alt="QR code scanner demo" width="320" />
</p>

| iOS 26+ | iOS 17.0 – 25 |
|---|---|
| Liquid-glass `ConcentricRectangle` pill | Smooth `RoundedRectangle` pill |

---

## Why this library?

- 🏝 **Dynamic Island animation** — expands from the pill at the top of the screen
- ⚡️ **100% native pipeline** — AVFoundation + SwiftUI, no JS or external dependencies.
- 🎨 **Fully configurable** — scan line color, height, speed, border, padding, hint text
- 📱 **iOS 26 liquid-glass** — `ConcentricRectangle` on iOS 26+, graceful fallback on older OS
- 🔒 **Automatic permissions** — requests camera access, shows a settings deep-link if denied
- 📳 **Haptic feedback** — device vibration on every successful scan
- 🧩 **Zero external dependencies** — no third-party npm packages are needed

---

## Quick Start

**1. Install**

```sh
npm install @ismnoiet/react-native-qrcode-scanner
# or
yarn add @ismnoiet/react-native-qrcode-scanner
```

**2. Install the native pod**

```sh
cd ios && pod install
```

**3. Add the camera permission** to `ios/<AppName>/Info.plist`:

```xml
<key>NSCameraUsageDescription</key>
<string>This app needs camera access to scan QR codes.</string>
```

**4. Use it**

```tsx
import { useState } from 'react';
import { Button, View } from 'react-native';
import { QRCodeScanner } from '@ismnoiet/react-native-qrcode-scanner';

export default function App() {
  const [scanning, setScanning] = useState(false);

  return (
    <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
      <Button title="Scan QR Code" onPress={() => setScanning(true)} />

      {/* Renders nothing until isScanning=true */}
      <QRCodeScanner
        isScanning={scanning}
        onClose={() => setScanning(false)}
        onScan={(e) => {
          console.log('Scanned:', e.nativeEvent.code);
          setScanning(false);
        }}
      />
    </View>
  );
}
```

---

## Requirements

| | Minimum |
|---|---|
| iOS | 17.0 |
| React Native | 0.73 |
| Xcode | 15 |
| Node | 20 |

---

## Example

A fully interactive demo — [`QRCodeScannerDemo.tsx`](./QRCodeScannerDemo.tsx) — is included in the repository. Making it a great starting point for integration and visual testing.

---

## API Reference

### Props

| Prop | Type | Default | Description |
|---|---|---|---|
| `isScanning` | `boolean` | **required** | Set `true` to open the scanner, `false` to close it |
| `onClose` | `() => void` | — | Called when the scanner dismisses — use to set `isScanning` back to `false` |
| `onScan` | `(e: ScanEvent) => void` | — | Callback fired once when a QR code is decoded |
| `scannerHintText` | `string` | `"Scan your QR code"` | Label shown below the camera viewport |
| `hintTextColor` | `string` | `"#FFFFFF99"` | Hex color of the hint text (`#RRGGBB` or `#RRGGBBAA`) |
| `hintTextSize` | `number` | `11` | Font size of the hint text in points |
| `showHintText` | `boolean` | `true` | Show or hide the hint text label |
| `scanLineColor` | `string` | `"#FFFFFF"` | Hex color of the animated scan line (`#RRGGBB` or `#RRGGBBAA`) |
| `scanLineHeight` | `number` | `2.5` | Thickness of the scan line in points |
| `showScanLine` | `boolean` | `true` | Show or hide the animated scan line |
| `scanLineSpeed` | `number` | `0.85` | Duration in seconds for one full sweep — lower is faster |
| `cameraBoxPadding` | `number` | `80` | Padding (points) around the camera viewport inside the expanded pill — larger shrinks the box |
| `cameraBorderColor` | `string` | `"#FFFFFF"` | Hex color of the rounded border around the camera viewport |
| `showCameraBorder` | `boolean` | `true` | Show or hide the camera viewport border |
| `cameraBackground` | `string` | `"#000000"` | Hex color of the scanner pill background (the area surrounding the camera feed) |

> `ScanEvent` = `NativeSyntheticEvent<QRCodeScannerEventData>`

### Event Data

```ts
interface QRCodeScannerEventData {
  /** The raw string decoded from the QR code. */
  code: string;
}
```

Access it via `event.nativeEvent.code`:

```tsx
onScan={(event) => {
  const qrValue = event.nativeEvent.code;
  console.log(qrValue);
}}
```

### TypeScript Types

All types are exported from the package entry point:

```ts
import type {
  QRCodeScannerProps,
  QRCodeScannerEventData,
} from '@ismnoiet/react-native-qrcode-scanner';
```

---

## Troubleshooting

### Camera permission dialog never appears
Ensure `NSCameraUsageDescription` is present in `Info.plist`. Without it iOS silently denies access and the app will crash in production.

### "QRCodeScanner native module not found"
Run `pod install` in the `ios/` directory and clean the build folder (`Product → Clean Build Folder` in Xcode).

### CocoaPods could not find compatible versions — higher minimum deployment target

```
[!] CocoaPods could not find compatible versions for pod "react-native-qrcode-scanner":
  In Podfile:
    react-native-qrcode-scanner (from `../node_modules/@ismnoiet/react-native-qrcode-scanner`)

Specs satisfying the `react-native-qrcode-scanner (from `../node_modules/@ismnoiet/react-native-qrcode-scanner`)` dependency were found, but they required a higher minimum deployment target.
```

Your app's iOS deployment target is below the minimum required by this pod (iOS 17.0). Open your `Podfile` and raise the platform version:

```ruby
platform :ios, '17.0'
```

Then re-run:

```sh
cd ios && pod install
```

If the target is set correctly in the `Podfile` but the error persists, also update the deployment target in Xcode: select your app target → **General** → **Minimum Deployments** → set iOS to **17.0** or higher.

---

## Acknowledgements

This module was inspired by [Dynamic Island QR Code Scanner by Kavsoft](https://www.youtube.com/watch?v=RMfpocBggJg).

---

## Contributing

1. Fork the repository
2. Create a feature branch: `git checkout -b feat/my-feature`
3. Make your changes
4. Test on a real device and simulator using `yarn ios`
5. Open a Pull Request

---

## License

MIT © [ismnoiet](https://github.com/ismnoiet)