Skip to main content
The Canvas component is the root container for all Skia drawing operations. It provides a surface where you can render shapes, images, text, and other graphical elements.

Basic Usage

import { Canvas, Circle } from "@shopify/react-native-skia";

export default function App() {
  return (
    <Canvas style={{ flex: 1 }}>
      <Circle cx={100} cy={100} r={50} color="blue" />
    </Canvas>
  );
}

Props

style
ViewStyle
React Native style object for positioning and sizing the canvas
mode
'default' | 'continuous'
default:"'default'"
Rendering mode:
  • default: Re-renders only when content changes
  • continuous: Continuously re-renders every frame (use for animations without Reanimated)
debug
boolean
default:"false"
Enables debug mode which displays frame timing information in development
opaque
boolean
default:"false"
If true, the canvas background is opaque. Can improve performance by skipping alpha blending.
onSize
SharedValue<SkSize>
Reanimated shared value that will be updated with the canvas size. Useful for responsive layouts.
colorSpace
'srgb' | 'p3'
default:"'p3'"
Color space for rendering:
  • srgb: Standard RGB color space
  • p3: Display P3 color space (wider gamut on supported devices)
ref
React.Ref<CanvasRef>
Reference to access canvas methods like makeImageSnapshot()
androidWarmup
boolean
default:"false"
Android only. Pre-initializes Skia context for faster first render.

Canvas Ref

Access canvas methods using a ref:
import { useRef } from "react";
import { Canvas, Circle, useCanvasRef } from "@shopify/react-native-skia";

export default function App() {
  const ref = useCanvasRef();
  
  const captureImage = () => {
    const snapshot = ref.current?.makeImageSnapshot();
    if (snapshot) {
      const base64 = snapshot.encodeToBase64();
      console.log("Captured:", base64);
    }
  };
  
  return (
    <Canvas ref={ref} style={{ width: 300, height: 300 }}>
      <Circle cx={150} cy={150} r={100} color="red" />
    </Canvas>
  );
}

Ref Methods

makeImageSnapshot
(rect?: SkRect) => SkImage
Synchronously captures the canvas content as an image. Optionally specify a rectangle to capture only a portion.
const snapshot = ref.current.makeImageSnapshot();
const partial = ref.current.makeImageSnapshot(rect(0, 0, 100, 100));
makeImageSnapshotAsync
(rect?: SkRect) => Promise<SkImage>
Asynchronously captures the canvas content. Preferred for animations or when rendering is in progress.
const snapshot = await ref.current.makeImageSnapshotAsync();
redraw
() => void
Forces the canvas to redraw immediately
ref.current.redraw();
getNativeId
() => number
Returns the native view ID of the canvas
measure
(callback: MeasureOnSuccessCallback) => void
Measures the canvas dimensions and position
ref.current.measure((x, y, width, height, pageX, pageY) => {
  console.log({ width, height });
});
measureInWindow
(callback: MeasureInWindowOnSuccessCallback) => void
Measures the canvas position relative to the window

Getting Canvas Size

Works on both old and new React Native architecture:
import { useSharedValue } from "react-native-reanimated";
import { Canvas, Circle } from "@shopify/react-native-skia";

export default function ResponsiveCanvas() {
  const size = useSharedValue({ width: 0, height: 0 });
  
  return (
    <Canvas style={{ flex: 1 }} onSize={size}>
      <Circle
        cx={() => size.value.width / 2}
        cy={() => size.value.height / 2}
        r={50}
        color="blue"
      />
    </Canvas>
  );
}

Using useCanvasSize Hook

import { Canvas, Circle, useCanvasSize } from "@shopify/react-native-skia";

export default function SizedCanvas() {
  const { ref, size } = useCanvasSize();
  
  return (
    <Canvas ref={ref} style={{ flex: 1 }}>
      {size.width > 0 && (
        <Circle
          cx={size.width / 2}
          cy={size.height / 2}
          r={50}
          color="green"
        />
      )}
    </Canvas>
  );
}

Rendering Modes

Default Mode

Re-renders only when props change (recommended for most use cases):
<Canvas style={{ flex: 1 }}>
  <Circle cx={100} cy={100} r={50} color="blue" />
</Canvas>

Continuous Mode

Re-renders every frame (use for animations without Reanimated):
import { useState, useEffect } from "react";
import { Canvas, Circle } from "@shopify/react-native-skia";

export default function ContinuousAnimation() {
  const [x, setX] = useState(0);
  
  useEffect(() => {
    const interval = setInterval(() => {
      setX((prev) => (prev + 1) % 300);
    }, 16);
    return () => clearInterval(interval);
  }, []);
  
  return (
    <Canvas mode="continuous" style={{ flex: 1 }}>
      <Circle cx={x} cy={150} r={30} color="red" />
    </Canvas>
  );
}

Performance Optimization

Opaque Canvas

Improve performance when transparency is not needed:
<Canvas opaque style={{ flex: 1 }}>
  {/* No transparency, faster rendering */}
  <Rect x={0} y={0} width={300} height={300} color="white" />
</Canvas>

Android Warmup

Pre-initialize Skia on Android for faster first render:
<Canvas androidWarmup style={{ flex: 1 }}>
  {/* First render will be faster */}
</Canvas>

Color Space

Choose appropriate color space for your content:
// For photos and rich graphics
<Canvas colorSpace="p3" style={{ flex: 1 }}>
  {/* Wider color gamut on supported devices */}
</Canvas>

// For standard content
<Canvas colorSpace="srgb" style={{ flex: 1 }}>
  {/* Standard sRGB colors */}
</Canvas>

Multiple Canvases

You can use multiple Canvas components in the same view:
import { View } from "react-native";
import { Canvas, Circle, Rect } from "@shopify/react-native-skia";

export default function MultiCanvas() {
  return (
    <View style={{ flex: 1 }}>
      <Canvas style={{ flex: 1, backgroundColor: "#f0f0f0" }}>
        <Circle cx={100} cy={100} r={50} color="red" />
      </Canvas>
      
      <Canvas style={{ flex: 1, backgroundColor: "#e0e0e0" }}>
        <Rect x={50} y={50} width={100} height={100} color="blue" />
      </Canvas>
    </View>
  );
}

Debug Mode

Enable debug information during development:
<Canvas debug style={{ flex: 1 }}>
  {/* Shows frame timing and other debug info */}
  <Circle cx={100} cy={100} r={50} color="purple" />
</Canvas>

Common Patterns

Responsive Design

import { useSharedValue } from "react-native-reanimated";
import { Canvas, Rect } from "@shopify/react-native-skia";

export default function ResponsiveRect() {
  const size = useSharedValue({ width: 0, height: 0 });
  
  return (
    <Canvas style={{ flex: 1 }} onSize={size}>
      <Rect
        x={0}
        y={0}
        width={() => size.value.width}
        height={() => size.value.height}
        color="cyan"
      />
    </Canvas>
  );
}

Screenshot Functionality

import { Button, View } from "react-native";
import { Canvas, Circle, useCanvasRef } from "@shopify/react-native-skia";

export default function Screenshot() {
  const ref = useCanvasRef();
  
  const takeScreenshot = async () => {
    const snapshot = await ref.current?.makeImageSnapshotAsync();
    const base64 = snapshot?.encodeToBase64();
    // Share or save the image
  };
  
  return (
    <View style={{ flex: 1 }}>
      <Canvas ref={ref} style={{ flex: 1 }}>
        <Circle cx={150} cy={150} r={100} color="orange" />
      </Canvas>
      <Button title="Take Screenshot" onPress={takeScreenshot} />
    </View>
  );
}

Build docs developers (and LLMs) love