logo-text
2D GraphicsAnimationsReact Native

React Native Skia Complete Guide: When, How, and Why to Use Skia for High-Performance Graphics

By Viewlytics Team16 min readMay 29, 2025

React Native Skia brings Google's powerful Skia 2D graphics library to React Native, enabling developers to create stunning custom graphics, animations, and interactive experiences with native performance. This comprehensive guide covers everything you need to know about leveraging Skia in your React Native applications.

What is React Native Skia?

React Native Skia is a library developed by Shopify that brings Google's Skia Graphics Library to React Native. Skia is the same 2D graphics engine that powers Google Chrome, Android UI, Flutter, and many other applications. With React Native Skia, you can create high-performance custom graphics, animations, and interactive components that run at 60+ FPS on both iOS and Android.

Key Features

  • High Performance: Native rendering with 60+ FPS animations
  • Cross-Platform: Write once, run on iOS, Android, and Web
  • Declarative API: React-like component structure for graphics
  • Rich Drawing Tools: Paths, shapes, gradients, filters, and more
  • Image Processing: Advanced image manipulation and effects
  • Animation Support: Smooth animations with React Native Reanimated

When to Use React Native Skia

Perfect Use Cases

✅ Ideal Scenarios
  • 📊 Custom charts and data visualizations
  • 🎮 2D games and interactive animations
  • 🎨 Drawing and sketching applications
  • 📐 Custom UI components with complex shapes
  • 🖼️ Image filters and photo editing
  • 📈 Real-time graphics and dashboards
  • 🎯 Custom progress indicators and loaders
⚠️ Consider Alternatives
  • 📱 Simple static UI components
  • 📝 Text-heavy applications
  • 🎬 Video playback (use Video components)
  • 🗺️ Maps (use dedicated map libraries)
  • 📋 Form inputs and standard controls
  • 🔗 Basic navigation and layouts

Getting Started with React Native Skia

Installation

Install React Native Skia using npm or yarn:

# npm
npm install @shopify/react-native-skia

# yarn
yarn add @shopify/react-native-skia

# pnpm
pnpm add @shopify/react-native-skia

For iOS, you need to run pod install:

cd ios && pod install

Basic Setup

Import and use the Canvas component to start drawing:

import React from 'react';
import { Canvas, Circle, Fill } from '@shopify/react-native-skia';

function BasicSkiaExample() {
  return (
    <Canvas style={{ flex: 1 }}>
      <Fill color="lightblue" />
      <Circle cx={100} cy={100} r={50} color="red" />
    </Canvas>
  );
}

Core Skia Components

Drawing Shapes

Skia provides various shape components for different drawing needs:

import {
  Canvas,
  Circle,
  Rect,
  RoundedRect,
  Path,
  Line,
  Polygon,
} from '@shopify/react-native-skia';

function ShapesExample() {
  return (
    <Canvas style={{ width: 300, height: 400 }}>
      {/* Circle */}
      <Circle cx={50} cy={50} r={30} color="red" />
      
      {/* Rectangle */}
      <Rect x={100} y={20} width={60} height={60} color="blue" />
      
      {/* Rounded Rectangle */}
      <RoundedRect
        x={200}
        y={20}
        width={60}
        height={60}
        rx={10}
        ry={10}
        color="green"
      />
      
      {/* Line */}
      <Line p1={{ x: 0, y: 100 }} p2={{ x: 300, y: 100 }} color="orange" strokeWidth={3} />
      
      {/* Polygon */}
      <Polygon
        points={[
          { x: 150, y: 120 },
          { x: 170, y: 160 },
          { x: 130, y: 160 },
        ]}
        color="purple"
      />
    </Canvas>
  );
}

Working with Paths

Paths are powerful for creating complex shapes and custom drawings:

import { Canvas, Path, Skia } from '@shopify/react-native-skia';

function PathExample() {
  // Create a star path
  const star = Skia.Path.Make();
  star.moveTo(150, 50);
  star.lineTo(160, 80);
  star.lineTo(190, 80);
  star.lineTo(170, 100);
  star.lineTo(180, 130);
  star.lineTo(150, 110);
  star.lineTo(120, 130);
  star.lineTo(130, 100);
  star.lineTo(110, 80);
  star.lineTo(140, 80);
  star.close();

  return (
    <Canvas style={{ width: 300, height: 200 }}>
      <Path path={star} color="gold" style="fill" />
      <Path path={star} color="orange" style="stroke" strokeWidth={2} />
    </Canvas>
  );
}

Advanced Features

Gradients and Effects

Create stunning visual effects with gradients and filters:

import {
  Canvas,
  Circle,
  LinearGradient,
  RadialGradient,
  Blur,
  DropShadow,
  vec,
} from '@shopify/react-native-skia';

function GradientExample() {
  return (
    <Canvas style={{ width: 300, height: 200 }}>
      {/* Linear Gradient */}
      <Circle cx={75} cy={75} r={50}>
        <LinearGradient
          start={vec(0, 0)}
          end={vec(150, 150)}
          colors={['#FF6B6B', '#4ECDC4']}
        />
      </Circle>
      
      {/* Radial Gradient with Blur */}
      <Circle cx={225} cy={75} r={50}>
        <RadialGradient
          c={vec(225, 75)}
          r={50}
          colors={['#A8E6CF', '#7FCDCD']}
        />
        <Blur blur={2} />
      </Circle>
      
      {/* Drop Shadow Effect */}
      <Circle cx={150} cy={150} r={40} color="white">
        <DropShadow dx={5} dy={5} blur={10} color="rgba(0,0,0,0.3)" />
      </Circle>
    </Canvas>
  );
}

Animations with Reanimated

Combine Skia with React Native Reanimated for smooth animations:

import React from 'react';
import { Canvas, Circle, Group } from '@shopify/react-native-skia';
import { useSharedValue, withRepeat, withTiming, useDerivedValue } from 'react-native-reanimated';

function AnimatedCircle() {
  const progress = useSharedValue(0);
  
  React.useEffect(() => {
    progress.value = withRepeat(
      withTiming(1, { duration: 2000 }),
      -1,
      true
    );
  }, []);

  const animatedProps = useDerivedValue(() => {
    const scale = 0.5 + progress.value * 0.5;
    const rotation = progress.value * 2 * Math.PI;
    
    return {
      transform: [
        { scale },
        { rotate: rotation },
      ],
    };
  });

  return (
    <Canvas style={{ width: 200, height: 200 }}>
      <Group {...animatedProps}>
        <Circle cx={100} cy={100} r={40} color="blue" />
      </Group>
    </Canvas>
  );
}

Real-World Examples

Custom Progress Circle

Build a customizable progress indicator:

import React from 'react';
import { Canvas, Circle, Path, Skia, Text, useFont } from '@shopify/react-native-skia';

type ProgressCircleProps = {
  progress: number; // 0 to 1
  size: number;
  strokeWidth: number;
  color: string;
}

function ProgressCircle(props: ProgressCircleProps) {
  const { progress, size, strokeWidth, color } = props;
  const radius = (size - strokeWidth) / 2;
  const circumference = 2 * Math.PI * radius;
  const strokeDasharray = circumference;
  const strokeDashoffset = circumference * (1 - progress);

  // Create circular path
  const path = Skia.Path.Make();
  path.addCircle(size / 2, size / 2, radius);

  return (
    <Canvas style={{ width: size, height: size }}>
      {/* Background circle */}
      <Circle
        cx={size / 2}
        cy={size / 2}
        r={radius}
        style="stroke"
        strokeWidth={strokeWidth}
        color="rgba(0,0,0,0.1)"
      />
      
      {/* Progress circle */}
      <Path
        path={path}
        style="stroke"
        strokeWidth={strokeWidth}
        color={color}
        strokeCap="round"
        strokeDasharray={[strokeDasharray]}
        strokeDashoffset={strokeDashoffset}
      />
      
      {/* Progress text */}
      <Text
        x={size / 2}
        y={size / 2}
        text={`${Math.round(progress * 100)}%`}
        color="black"
        size={16}
        textAlign="center"
      />
    </Canvas>
  );
}

Interactive Drawing Canvas

Create a drawing app with gesture handling:

import React from 'react';
import { Canvas, Path, Skia } from '@shopify/react-native-skia';
import { Gesture, GestureDetector } from 'react-native-gesture-handler';
import { useSharedValue } from 'react-native-reanimated';

function DrawingCanvas() {
  const paths = useSharedValue([]);
  const currentPath = useSharedValue(null);

  const panGesture = Gesture.Pan()
    .onStart((event) => {
      const newPath = Skia.Path.Make();
      newPath.moveTo(event.x, event.y);
      currentPath.value = newPath;
    })
    .onUpdate((event) => {
      if (currentPath.value) {
        currentPath.value.lineTo(event.x, event.y);
      }
    })
    .onEnd(() => {
      if (currentPath.value) {
        paths.value = [...paths.value, currentPath.value];
        currentPath.value = null;
      }
    });

  return (
    <GestureDetector gesture={panGesture}>
      <Canvas style={{ flex: 1 }}>
        {paths.value.map((path, index) => (
          <Path
            key={index}
            path={path}
            style="stroke"
            strokeWidth={3}
            color="blue"
            strokeCap="round"
            strokeJoin="round"
          />
        ))}
        {currentPath.value && (
          <Path
            path={currentPath.value}
            style="stroke"
            strokeWidth={3}
            color="blue"
            strokeCap="round"
            strokeJoin="round"
          />
        )}
      </Canvas>
    </GestureDetector>
  );
}

Performance Optimization

Best Practices

  • Use useMemo for Complex Paths: Cache expensive path calculations
  • Minimize Redraws: Only update when necessary using useSharedValue
  • Optimize Image Processing: Use appropriate image formats and sizes
  • Batch Operations: Group multiple drawing operations when possible
  • Profile Performance: Use React Native Performance Monitor
import React, { useMemo } from 'react';
import { Canvas, Path, Skia } from '@shopify/react-native-skia';

function OptimizedComponent({ data }) {
  // Memoize expensive path creation
  const chartPath = useMemo(() => {
    const path = Skia.Path.Make();
    data.forEach((point, index) => {
      if (index === 0) {
        path.moveTo(point.x, point.y);
      } else {
        path.lineTo(point.x, point.y);
      }
    });
    return path;
  }, [data]);

  return (
    <Canvas style={{ width: 300, height: 200 }}>
      <Path path={chartPath} style="stroke" color="blue" strokeWidth={2} />
    </Canvas>
  );
}

Common Patterns and Tips

Working with Images

Load and manipulate images efficiently:

import { Canvas, Image, useImage } from '@shopify/react-native-skia';

function ImageExample() {
  const image = useImage(require('./assets/sample.png'));

  if (!image) {
    return null; // Loading state
  }

  return (
    <Canvas style={{ width: 300, height: 200 }}>
      <Image
        image={image}
        x={0}
        y={0}
        width={300}
        height={200}
        fit="cover"
      />
    </Canvas>
  );
}

Text Rendering

Render custom text with fonts:

import { Canvas, Text, useFont } from '@shopify/react-native-skia';

function TextExample() {
  const font = useFont(require('./assets/fonts/custom-font.ttf'), 24);

  if (!font) {
    return null;
  }

  return (
    <Canvas style={{ width: 300, height: 100 }}>
      <Text
        x={20}
        y={50}
        text="Custom Text Rendering"
        font={font}
        color="darkblue"
      />
    </Canvas>
  );
}

Troubleshooting Common Issues

Performance Issues

  • Excessive Redraws: Check for unnecessary state updates in parent components
  • Memory Leaks: Properly dispose of large images and complex paths
  • Animation Stuttering: Ensure animations run on the UI thread with useSharedValue

Platform-Specific Considerations

  • iOS: Some gradient effects may render differently; test on device
  • Android: Ensure proper hardware acceleration is enabled
  • Web: Limited WebGL support may affect complex operations

Conclusion

React Native Skia is a powerful tool for creating high-performance graphics and animations in React Native applications. It's particularly valuable for data visualization, custom UI components, and interactive experiences that require smooth animations and complex drawing operations.

When deciding whether to use Skia, consider the complexity of your graphics needs, performance requirements, and development timeline. For simple UI elements, standard React Native components may be sufficient. However, for custom charts, drawing applications, or complex animations, Skia provides unmatched performance and flexibility.

Start with simple examples and gradually build complexity as you become more comfortable with the API. The combination of Skia's power and React Native's cross-platform capabilities opens up exciting possibilities for creating truly native-feeling applications with stunning visual experiences.

🚀 Ready to catch UI issues before your users do?

Use Viewlytics to automatically capture and analyze your app's UI across real devices. Our AI-powered platform helps you identify visual bugs, layout issues, and inconsistencies before they impact user experience.

Start UI Testing with Viewlytics
logo

2025 © Viewlytics. All rights reserved.