React QR Code

React Native

The same ReactQRCode component works in React Native and Expo apps. It renders through react-native-svg and supports every style, gradient, logo and frame option that the web version does.

Requirements

  • React Native 0.82 or later (the New Architecture), or Expo SDK 55+.
  • react-native-svg 15 or later.

Installation

Install the library together with react-native-svg. In an Expo app, expo install picks the react-native-svg version that matches your SDK.

$ npx expo install @lglab/react-qr-code react-native-svg

Expo Go already includes react-native-svg. In a bare React Native app or an Expo development build, rebuild the app after installing, for example with npx react-native run-android. On iOS, run npx pod-install before the rebuild.

Usage

Import the component as you would on the web. Metro picks the React Native build from the package's react-native export condition, and Expo web keeps using the DOM build.

tsx
1import { ReactQRCode } from '@lglab/react-qr-code'
2
3export const Ticket = () => {
4 return (
5 <ReactQRCode
6 value='https://reactqrcode.com'
7 size={240}
8 dataModulesSettings={{ style: 'rounded' }}
9 frameSettings={{ style: 'banner-bottom', text: 'Scan me!' }}
10 />
11 )
12}

Exporting a PNG

There is no file download on a phone, so the native ref has no download(). Use toDataURL() instead. It resolves with a PNG data URL that is size pixels wide, the same as the component's size unless you pass one. The web ref has the same method.

tsx
1import { useRef } from 'react'
2import { Button } from 'react-native'
3import { ReactQRCode, type ReactQRCodeRef } from '@lglab/react-qr-code'
4
5export const Share = () => {
6 const ref = useRef<ReactQRCodeRef>(null)
7
8 const exportPng = async () => {
9 // Resolves with "data:image/png;base64,..."
10 const png = await ref.current?.toDataURL({ size: 1024 })
11 // Show it with <Image source={{ uri: png }} />, or write the base64
12 // part to a file with expo-file-system and share it.
13 }
14
15 return (
16 <>
17 <ReactQRCode ref={ref} value='https://reactqrcode.com' />
18 <Button title='Export PNG' onPress={exportPng} />
19 </>
20 )
21}

Logos

imageSettings.src takes a URL or a bundled image from require().

tsx
1<ReactQRCode
2 value='https://reactqrcode.com'
3 imageSettings={{
4 src: require('./assets/logo.png'),
5 width: 48,
6 height: 48,
7 excavate: true,
8 }}
9/>

Differences from the web

  • ref.current.svg is the react-native-svg Svg instance, and the ref has toDataURL() but no download().
  • svgProps are react-native-svg SvgProps, so use testID, style and accessibility props there.
  • Frame labels use the system font by default. To use another, load it in your app (for example with expo-font) and pass its name as frameSettings.fontFamily.
  • Labels too long for the frame are squeezed horizontally to fit, because react-native-svg does not support textLength.
  • imageSettings.crossOrigin has no effect.

Expo web

On Expo web the package loads its DOM build, so web rules apply there: pass imageSettings.src as a URL rather than a require(), and keep svgProps to props a DOM svg accepts. TypeScript in an Expo project uses the React Native types, so it will not flag these.

Testing with Jest

The React Native build is an ES module, so add @lglab to the packages Jest transforms. With the jest-expo preset:

json
1{
2 "jest": {
3 "preset": "jest-expo",
4 "transformIgnorePatterns": [
5 "node_modules/(?!(\\.pnpm|react-native|@react-native|@react-native-community|expo|@expo|react-native-svg|@lglab))"
6 ]
7 }
8}