Skip to main content

Canvas

The Canvas component is the root of your Skia drawing. You can treat it as a regular React Native view and assign a view style. Behind the scenes, it is using its own React renderer.

NameTypeDescription.
style?ViewStyleView style
ref?Ref<SkiaView>Reference to the SkiaView object
onSize?SharedValue<Size>Reanimated value to which the canvas size will be assigned (see canvas size)

Canvas size

The size of the canvas is available on both the UI and JS thread.

UI thread

The onSize property receives a shared value, which will be updated whenever the canvas size changes. You can see it in action in the example below.

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

const Demo = () => {
// size will be updated as the canvas size changes
const size = useSharedValue({ width: 0, height: 0 });
const rect = useDerivedValue(() => {
const {width, height} = size.value;
return { x: 0, y: 0, width, height };
});
return (
<Canvas style={{ flex: 1 }} onSize={size}>
<Rect color="cyan" rect={rect} />
</Canvas>
);
};

JS thread

To get the canvas size on the JS thread, you can use useLayoutEffect and measure(). Since this is a very common pattern, we offer a useCanvasSize hook you can use for convenience.

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

const Demo = () => {
const {ref, size: {width, height}} = useCanvasSize();
return (
<Canvas style={{ flex: 1 }} ref={ref}>
<Rect color="cyan" rect={{ x: 0, y: 0, width, height }} />
</Canvas>
);
};

This example is equivalent to the code below:

import {useLayoutEffect, useState} from "react";
import {Fill, Canvas, Rect, useCanvasRef} from "@shopify/react-native-skia";

const Demo = () => {
const ref = useCanvasRef();
const [rect, setRect] = useState({ x: 0, y: 0, width: 0, height: 0 });
useLayoutEffect(() => {
ref.current?.measure((_x, _y, width, height) => {
setRect({ x: 0, y: 0, width, height });
});
}, []);
return (
<Canvas style={{ flex: 1 }} ref={ref}>
<Rect color="cyan" rect={rect} />
</Canvas>
);
};

Getting a Canvas Snapshot

You can save your drawings as an image by using the makeImageSnapshotAsync method. This method returns a promise that resolves to an Image. It executes on the UI thread, ensuring access to the same Skia context as your on-screen canvases, including textures.

If your drawing does not contain textures, you may also use the synchronous makeImageSnapshot method for simplicity.

Example

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

export const Demo = () => {
const ref = useCanvasRef();
useEffect(() => {
setTimeout(() => {
// you can pass an optional rectangle
// to only save part of the image
const image = ref.current?.makeImageSnapshot();
if (image) {
// you can use image in an <Image> component
// Or save to file using encodeToBytes -> Uint8Array
const bytes = image.encodeToBytes();
console.log({ bytes });
}
}, 1000)
});
return (
<Canvas style={{ flex: 1 }} ref={ref}>
<Circle r={128} cx={128} cy={128} color="red" />
</Canvas>
);
};

Accessibility

The Canvas component supports the same properties as a View component including its accessibility properties. You can make elements inside the canvas accessible as well by overlayings views on top of your canvas. This is the same recipe used for applying gestures on specific canvas elements.