{"id":11808,"library":"react-native-view-shot","title":"React Native ViewShot","description":"react-native-view-shot is a utility library for React Native applications, enabling developers to capture any rendered view or the entire screen as an image. It provides functionalities to save the captured image to a file, retrieve it as a Base64 encoded string, or other raw formats. The library is actively maintained, with version 4.0.3 being the current stable release, demonstrating a consistent cadence of updates to support the latest versions of React Native, iOS, and Android platforms. Key differentiators include its robust handling of various view types, including SurfaceView on Android, and continuous improvements in performance and platform compatibility, making it a reliable solution for screenshot and view snapshot requirements within the React Native ecosystem. It also offers dedicated web support since v3.7.0.","status":"active","version":"4.0.3","language":"javascript","source_language":"en","source_url":"https://github.com/gre/react-native-view-shot","tags":["javascript","react-native","screenshot","viewshot","view-snapshot","snapshot","rasterize","typescript"],"install":[{"cmd":"npm install react-native-view-shot","lang":"bash","label":"npm"},{"cmd":"yarn add react-native-view-shot","lang":"bash","label":"yarn"},{"cmd":"pnpm add react-native-view-shot","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"Required for all React Native applications.","package":"react","optional":false},{"reason":"Core React Native framework.","package":"react-native","optional":false}],"imports":[{"note":"Primarily used with `useRef` to capture a specific component instance. CommonJS `require` is generally not recommended in modern React Native projects due to Metro's ESM preference.","wrong":"const captureRef = require('react-native-view-shot').captureRef","symbol":"captureRef","correct":"import { captureRef } from 'react-native-view-shot'"},{"note":"ViewShot is a default export. Attempting to import it as a named export `{ ViewShot }` will result in an undefined module. It is used as a wrapper component for content intended for capture.","wrong":"import { ViewShot } from 'react-native-view-shot'","symbol":"ViewShot","correct":"import ViewShot from 'react-native-view-shot'"},{"note":"Captures the entire device screen without requiring a wrapper component. Note its functionality, particularly on iOS, was improved and fixed in v3.3.0.","wrong":"import ViewShot, { captureScreen } from 'react-native-view-shot'","symbol":"captureScreen","correct":"import { captureScreen } from 'react-native-view-shot'"},{"note":"TypeScript type for defining capture parameters such as format, quality, width, height, and file name. Essential for type-safe configuration of capture operations.","symbol":"CaptureOptions","correct":"import type { CaptureOptions } from 'react-native-view-shot'"}],"quickstart":{"code":"import React, { useRef, useState } from 'react';\nimport { Button, View, Text, Alert, Image, StyleSheet } from 'react-native';\nimport ViewShot from 'react-native-view-shot';\nimport { CameraRoll } from '@react-native-camera-roll/camera-roll'; // Peer dependency for saving\n\n// Note: @react-native-camera-roll/camera-roll requires separate installation and linking,\n// as well as appropriate permissions (e.g., WRITE_EXTERNAL_STORAGE on Android, NSPhotoLibraryUsageDescription on iOS).\n\nconst MyViewCapture = () => {\n  const viewShotRef = useRef<ViewShot>(null);\n  const [capturedUri, setCapturedUri] = useState<string | null>(null);\n\n  const captureView = async () => {\n    if (viewShotRef.current) {\n      try {\n        // Capture the view with specified options\n        const uri = await viewShotRef.current.capture();\n        setCapturedUri(uri);\n        console.log('Image captured to:', uri);\n        Alert.alert('Capture Success', `Image URI: ${uri}`);\n        \n        // Optional: Save to camera roll (requires @react-native-camera-roll/camera-roll and permissions)\n        // try {\n        //   const result = await CameraRoll.save(uri, { type: 'photo' });\n        //   Alert.alert('Saved', `Image saved to camera roll: ${result}`);\n        // } catch (saveError) {\n        //   console.error('Failed to save to camera roll:', saveError);\n        //   Alert.alert('Save Error', `Failed to save image: ${saveError}`);\n        // }\n\n      } catch (error) {\n        console.error('Failed to capture view:', error);\n        Alert.alert('Capture Error', `Failed to capture view: ${error}`);\n      }\n    } else {\n      Alert.alert('Error', 'ViewShot ref is not available.');\n    }\n  };\n\n  return (\n    <View style={styles.container}>\n      <ViewShot ref={viewShotRef} options={{ format: 'png', quality: 0.9, result: 'data-uri' }} style={styles.captureTarget}>\n        <Text style={styles.title}>Hello ViewShot!</Text>\n        <Text style={styles.subtitle}>This is a component that will be captured as an image.</Text>\n        <Image \n          source={{ uri: 'https://via.placeholder.com/100/ADD8E6/000000?text=RN' }} \n          style={styles.image}\n        />\n      </ViewShot>\n\n      {capturedUri && (\n        <View style={styles.previewContainer}>\n          <Text style={styles.previewText}>Captured Image Preview:</Text>\n          <Image source={{ uri: capturedUri }} style={styles.previewImage} resizeMode=\"contain\" />\n        </View>\n      )}\n\n      <Button title=\"Capture View\" onPress={captureView} />\n    </View>\n  );\n};\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    justifyContent: 'center',\n    alignItems: 'center',\n    backgroundColor: '#f0f0f0',\n    padding: 20,\n  },\n  captureTarget: {\n    backgroundColor: 'white',\n    padding: 20,\n    borderRadius: 10,\n    alignItems: 'center',\n    marginBottom: 30,\n  },\n  title: {\n    fontSize: 24,\n    fontWeight: 'bold',\n    marginBottom: 10,\n  },\n  subtitle: {\n    fontSize: 16,\n    textAlign: 'center',\n    marginBottom: 15,\n  },\n  image: {\n    width: 100,\n    height: 100,\n    borderRadius: 5,\n  },\n  previewContainer: {\n    marginTop: 20,\n    alignItems: 'center',\n    marginBottom: 20,\n  },\n  previewText: {\n    fontSize: 18,\n    fontWeight: 'bold',\n    marginBottom: 10,\n  },\n  previewImage: {\n    width: 250,\n    height: 250,\n    borderWidth: 1,\n    borderColor: '#ccc',\n    backgroundColor: '#e8e8e8',\n  },\n});\n\nexport default MyViewCapture;","lang":"typescript","description":"Demonstrates how to use the `ViewShot` component with a `useRef` hook to capture a specific React Native view. The example sets capture options for PNG format and logs the resulting image URI, also showing an optional preview. Saving to the camera roll is commented out as it requires additional setup and permissions."},"warnings":[{"fix":"Review existing capture configurations that specify `width` or `height` on Android and adjust them to the desired absolute pixel dimensions. Test capture outputs thoroughly after upgrading.","message":"The `width` and `height` options for capture on Android were fixed in v3.4.0 to represent absolute pixel dimensions. If you relied on a previous, potentially buggy behavior where these dimensions were interpreted differently or scaled incorrectly, your captures might change in size or aspect ratio after upgrading.","severity":"breaking","affected_versions":"<3.4.0"},{"fix":"Add necessary permissions to `AndroidManifest.xml` and `Info.plist`. Implement a runtime permission request using a library like `react-native-permissions` before attempting to save captured images.","message":"Saving captured images to the device's camera roll or external storage requires appropriate runtime permissions. For Android, `WRITE_EXTERNAL_STORAGE` is needed; for iOS, `NSPhotoLibraryUsageDescription` must be added to `Info.plist`. Without these, attempts to save will fail with permission errors.","severity":"gotcha","affected_versions":">=2.0.0"},{"fix":"Ensure you are running `react-native-view-shot` at version `3.0.2` or later to avoid this regression. If encountering issues with `<ViewShot>` in these versions, upgrade immediately.","message":"The `<ViewShot>` component experienced a temporary regression around versions v3.0.0 and v3.0.1, causing it to be broken due to issues with `captureMode` checks. This was addressed and fixed in v3.0.2.","severity":"gotcha","affected_versions":"=3.0.0, =3.0.1"},{"fix":"Upgrade `react-native-view-shot` to v3.3.0 or higher for improved `captureScreen` stability and functionality on iOS.","message":"`captureScreen` functionality on iOS had reported issues and received fixes in v3.3.0. If you are targeting older iOS versions with a version of `react-native-view-shot` prior to v3.3.0, `captureScreen` might not work reliably.","severity":"gotcha","affected_versions":"<3.3.0"}],"env_vars":null,"last_verified":"2026-04-19T00:00:00.000Z","next_check":"2026-07-18T00:00:00.000Z","problems":[{"fix":"Ensure `viewShotRef` is initialized with `useRef(null)` and passed as `ref={viewShotRef}` to the `ViewShot` component. Wrap the `capture()` call in a check `if (viewShotRef.current)` to ensure the component is mounted before attempting to capture.","cause":"The `useRef` hook's current property is null when `capture()` is called, indicating that the `ViewShot` component has not yet mounted or the ref is not correctly attached.","error":"TypeError: Cannot read property 'capture' of null"},{"fix":"Change the import statement from `import { ViewShot } from 'react-native-view-shot'` to `import ViewShot from 'react-native-view-shot'`.","cause":"`ViewShot` is exported as a default module, but the import statement is attempting to destructure it as a named export.","error":"Invariant Violation: `ViewShot` has been imported by a default import (as `ViewShot`) but is a named export (as `ViewShot`)."},{"fix":"For Android, add `<uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\" />` to `AndroidManifest.xml`. For iOS, add `NSPhotoLibraryUsageDescription` to `Info.plist`. Additionally, request these permissions at runtime if targeting modern Android versions (API 23+) or iOS.","cause":"The React Native application lacks the necessary platform-specific permissions to save the captured image to the device's storage or photo library.","error":"Error: No permission to write to storage. Please check your app's permissions."},{"fix":"Ensure `react-native-view-shot` is updated to a version compatible with your current React Native installation. Try upgrading `react-native-view-shot` to its latest stable release, then perform a clean Android build by running `cd android && ./gradlew clean && cd ..` before rebuilding your app.","cause":"This Android build error often occurs due to a mismatch between the `react-native-view-shot` version and your `react-native` version, indicating an incompatibility with native module API changes.","error":"Error: RNViewShotModule.java:xx: error: cannot find symbol method getArguments() in ReadableNativeMap"}],"ecosystem":"npm"}