Native-quality view capture for React Native’s New Architecture, powered by Nitro Modules.
Viewsnap clones the behaviour of react-native-view-shot, but ships as a Nitro module that only targets the Fabric renderer for maximal performance and minimal bridge overhead.
- 🚀 Fabric-only implementation – no legacy bridge fallback.
- 📦 Tree-shakable API (
captureRef+useViewsnap), no side effects on import. - 🎯 Imperative control via
captureRef(ref, options). - 🪝 Declarative ergonomics with
useViewsnap. - 🎨 Configurable output: PNG/JPEG/WebP (Android), base64/data URI/tmpfile.
- 🖼️ High-resolution captures with custom scaling and size overrides.
- ⚡ Optimised rendering: skips redundant redraws, optional clipping relaxation.
- React Native 0.72+ with New Architecture (Fabric) enabled.
- Nitro Modules properly installed in the host app.
- iOS 13+ / Android API 21+ (WebP output uses Android API 30+; falls back to PNG otherwise).
❗ Viewsnap does not support the legacy architecture –
RCT_NEW_ARCH_ENABLED=1must be set for builds.
npm install react-native-viewsnap
# or
yarn add react-native-viewsnapEnsure Nitro Modules are initialised inside your app following the official guide.
After installing dependencies:
cd ios && pod installOn Android, sync Gradle or rebuild the project so the generated Nitro sources are compiled.
import { captureRef } from 'react-native-viewsnap'
import { useRef } from 'react'
import { View } from 'react-native'
export function SnapshotExample() {
const targetRef = useRef<View>(null)
async function onCapture() {
const uri = await captureRef(targetRef, {
format: 'jpg',
quality: 0.85,
result: 'tmpfile'
})
console.log('Snapshot stored at:', uri)
}
return (
<View ref={targetRef}>
{/* ... */}
</View>
)
}import { useViewsnap } from 'react-native-viewsnap'
import { useCallback, useRef } from 'react'
import { Pressable, View } from 'react-native'
export function CaptureButton() {
const ref = useRef<View>(null)
const snap = useViewsnap({ format: 'png', result: 'data-uri' })
const handlePress = useCallback(async () => {
const dataUri = await snap(ref)
// do something with dataUri
}, [snap])
return (
<>
<View ref={ref} />
<Pressable onPress={handlePress}>{/* ... */}</Pressable>
</>
)
}Both APIs accept either a numeric native tag or a ref created via useRef, createRef, or legacy class component refs.
| Option | Type | Default | Description |
|---|---|---|---|
format |
'png' | 'jpg' | 'webp' |
'png' |
Output encoding. WebP falls back to PNG on iOS or when unsupported. |
quality |
number (0-1) |
1 |
Compression quality for lossy formats (jpg, webp). Ignored for PNG. |
result |
'tmpfile' | 'base64' | 'data-uri' |
'tmpfile' |
Return type: temp file path, base64 string, or data URI. |
fileName |
string |
Random UUID | Custom filename (without extension) when result="tmpfile". |
width / height |
number |
Captured view size × scale | Output dimensions in physical pixels. Preserves aspect ratio when only one is provided. |
scale |
number |
PixelRatio.get() (JS) / device density (native) |
Additional scale multiplier applied before rendering. Must be > 0. |
includeNonVisibleSubviews |
boolean |
true |
Disable parent clipping while rendering to include overflowing children. |
skipRedraw |
boolean |
false |
When true, skips drawHierarchyAfterUpdates / invalidate to save work if the view is already up to date. |
package.jsonsets"sideEffects": false.- Nitro module creation is lazy – importing
react-native-viewsnapdoes not register native code untilcaptureRef/useViewsnapruns.
This allows bundlers (Metro, Webpack) to drop any unused exports automatically.
Whenever you edit src/specs/Viewsnap.nitro.ts, regenerate bindings:
npx tsc --noEmit
npx nitrogen --logLevel=debugCommit the updated files under nitrogen/generated/ alongside your source changes.
- iOS: Resolves Fabric
UIViewviaRCTSurfacePresenter, captures withUIGraphicsImageRenderer, and writes to disk or encodes in-memory as requested. - Android: Resolves
FabricUIManager, captures on the UI thread into a scaledBitmap, and encodes usingBitmap.compress. - Both variants relax clipping when
includeNonVisibleSubviewsistrue, and validate scale/bounds to fail fast with descriptive errors.
Viewsnap module is not available– ensure Nitro Modules are initialised before JS runs and the app is rebuilt after installation.Fabric SurfacePresenter is unavailable/NewArchitectureOnly– check that New Architecture is enabled (hermes,fabric,useFabricflags,RCT_NEW_ARCH_ENABLED=1).- Blank captures – confirm the ref resolves to a mounted host view and optionally disable
skipRedraw.
MIT © 2025 Margelo / Maintainers. See LICENSE if present or the package metadata for details.