suiss/uim · React Native Component

Qr Scanner

A camera overlay with a rounded cut-out scan frame, rounded corner brackets, an optional scan line and an optional flashlight toggle.

Qr Scanner is an open-source mobile component from suiss/uim for React Native and Expo, with SwiftUI and Jetpack Compose versions built from the same design tokens. The @esuiss/uim CLI copies its source into your project, so you own the code.

iOS
Qr Scanner on iOS in light mode

QRScanner is a View that draws an overlay on top of whatever you pass as children, usually a camera preview. It does not open the camera itself. The overlay dims everything outside a square frame with rounded corners (drawn with react-native-svg) and marks the frame with four rounded corner brackets. When scanLine is set, a line moves up and down inside the frame with Reanimated while the state is idle.

The frame size defaults to 66% of the shorter side, capped at 260 points. It is centered horizontally and sits slightly above the vertical center. A title sits above the frame and a description below it; the flashlight button sits near the bottom edge.

Installation

$ pnpm dlx @esuiss/uim@latest add qr-scanner

The CLI also adds what it builds on: Icon, Text.

Manual

  1. Install the dependencies:
npx expo install cn phosphor-react-native react-native-reanimated react-native-svg react-native-worklets
  1. Add the pieces it builds on: Icon, Text, and the primitives components/primitives/haptics.tsx, components/primitives/hooks.tsx.

  2. Copy the source into components/ui/qr-scanner.tsx:

uniwind/components/ui/qr-scanner.tsx
import { cn } from "cn"
import {
  FlashlightIcon,
  type IconProps as PhosphorIconProps,
} from "phosphor-react-native"
import * as React from "react"
import { Pressable, View } from "react-native"
import Animated, {
  cancelAnimation,
  Easing,
  ReduceMotion,
  useAnimatedProps,
  useAnimatedStyle,
  useReducedMotion,
  useSharedValue,
  withRepeat,
  1. Update the import paths to match your project.

Usage

import { QRScanner } from "@/components/ui/qr-scanner"
<Scanner description="Point your camera at a code to pay or connect." />

Render your camera view as children and size the scanner with className. When there are no children, the background falls back to bg-media.

Set state to success or error after you read a code. The brackets fade to a matching color, success springs the frame slightly smaller and error shakes it. Pass onTorchToggle together with a controlled torch value to show the flashlight button; leave it out to hide the button. title and description accept strings or your own elements.

The QRScannerState type is also exported.

Examples

Success

The success state with green brackets and a slightly smaller frame.

iOS
Qr Scanner (success) on iOS in light mode

Error

The error state, which shakes the frame and turns the brackets red.

iOS
Qr Scanner (error state) on iOS in light mode

With scan line

The scanner with scanLine turned on.

iOS
Qr Scanner (with scan line) on iOS in light mode

Without torch

A title and description with no flashlight button, because onTorchToggle is not passed.

iOS
Qr Scanner (without torch) on iOS in light mode

API Reference

QRScanner

ExtendsReact.ComponentProps<typeof View>
PropType
About
idle, success or error. Sets the bracket color and triggers haptics, the success scale and the error shake. Defaults to idle.
Type
QRScannerState
Default
"idle"
About
Content shown above the frame. Strings are wrapped in a Text.
Type
React.ReactNode
Default
—
About
Content shown below the frame. Strings are wrapped in a Text.
Type
React.ReactNode
Default
—
About
Shows the animated scan line while the state is idle. Defaults to false.
Type
boolean
Default
false
About
Whether the flashlight is on. The button fills and the icon uses the fill weight when on. Defaults to false.
Type
boolean
Default
false
About
Called with the next torch value when the flashlight button is pressed. The button is shown only when this is set.
Type
(torch: boolean) => void
Default
—
About
Accessibility label for the flashlight button. Defaults to "Flashlight".
Type
string
Default
"Flashlight"
About
Side length of the scan frame in points. Overrides the automatic size.
Type
number
Default
—

Accessibility

  • The dimmed surround and brackets are hidden from VoiceOver and TalkBack.
  • The overlay is a polite live region, so changes to the title and description are announced on Android.
  • The flashlight button has the button role, uses torchLabel as its label and reports torch as its selected state.
  • State changes to success and error play a matching haptic notification.
  • The shake and scan-line animations respect the system reduce motion setting, and the success scale is skipped when reduce motion is on.

Notes

  • Uses the bg-media, text-scrim, text-on-media, text-success, text-danger and bg-accent tokens; the flashlight button uses bg-scrim when off and bg-on-media with a text-media icon when on.
  • The scan line restarts whenever the state returns to idle.