Getting Started
Installation
Requires React 19+, React Native 0.79+ with the New Architecture, Skia 2.x (2.15.1+), Reanimated 4.x (4.1.7+), Worklets 0.7+, and Gesture Handler 2 or 3. Choose a compatible Reanimated/Worklets pair for your React Native version using the compatibility table.
yarn add react-native-reanimated@^4.1.7 react-native-worklets "react-native-gesture-handler@^2 || ^3" react-native-skia@^2.15.1
For a bare React Native app, add "react-native-worklets/plugin" last in your babel.config.js plugins. Expo's babel-preset-expo configures it automatically. Rebuild your native app after installation (run pod install for iOS).
This release uses the renamed react-native-skia package on Skia 2.x. Skia 3 is not supported. If you previously installed @shopify/react-native-skia, follow the migration guide before upgrading. The scoped and unscoped packages must not be installed together.
Then install victory-native:
yarn add victory-native
Now you should be ready to go.
Your first chart
Let's create a basic line chart on a Cartesian grid. Let's mock out a little bit of mock data for "high temperature" for each day in a month:
const DATA = Array.from({ length: 31 }, (_, i) => ({
day: i,
highTmp: 40 + 30 * Math.random(),
}));
Instantiate a chart
Now, we'll use the CartesianChart component and pass in our data, specifying which property we'll be using for our x (independent variable) and y (dependent variable) keys.
import { View } from "react-native";
import { CartesianChart } from "victory-native";
// ...
function MyChart() {
return (
<View style={{ height: 300 }}>
// 👇 start our chart
<CartesianChart data={DATA} xKey="day" yKeys={["highTmp"]} />
</View>
);
}
At this point, we're you'll just see a blank view, since we aren't rendering anything useful to our charting canvas.
Add a line to the chart
The CartesianChart uses a render function for its children prop. To render content inside of the Cartesian chart, you return Skia elements from the children render function. We'll use the Line component from victory-native to render a line path using our temperature data.
import { View } from "react-native";
import { CartesianChart, Line } from "victory-native";
function MyChart() {
return (
<View style={{ height: 300 }}>
<CartesianChart data={DATA} xKey="day" yKeys={["highTmp"]}>
{/* 👇 render function exposes various data, such as points. */}
{({ points }) => (
// 👇 and we'll use the Line component to render a line path.
<Line points={points.highTmp} color="red" strokeWidth={3} />
)}
</CartesianChart>
</View>
);
}
Now we've got a line path to represent our daily high temperature data!

Add some axes
You might want some axes to make your line graph a bit easier to read and interpret. The CartesianChart offers out-of-the-box support for axes and grids to make it easy to get up and running with some axes. Let's add some now.
import { View } from "react-native";
import { CartesianChart, Line } from "victory-native";
// 👇 import a font file you'd like to use for tick labels
import inter from "../assets/inter-medium.ttf";
function MyChart() {
const font = useFont(inter, 12);
return (
<View style={{ height: 300 }}>
<CartesianChart
data={DATA}
xKey="day"
yKeys={["highTmp"]}
// 👇 pass the font, opting in to axes.
axisOptions={{ font }}
>
{({ points }) => (
<Line points={points.highTmp} color="red" strokeWidth={3} />
)}
</CartesianChart>
</View>
);
}
And now we've got some axes and grid lines!

Adding a tooltip
You might also want to give your users a way to interact with the line chart you've created. Handling user gestures can be complex, especially in canvas-like drawing context. Victory Native helps streamline this for you. To build a basic tooltip, we'll do three things.
- Create a
ChartPressStateinstance using theuseChartPressStatehook fromvictory-native. - Pass our state variable into our
<CartesianChart />element. - Use the Reanimated shared values from the
ChartPressStateinstance in a customToolTipcomponent that we'll create to create our tooltip element.
We'll start by creating our ChartPressState instance and pass it to our chart element.
// ...
import { /*...*/ useChartPressState } from "victory-native";
function MyChart() {
// ...
// 👇 create our chart press state
const { state, isActive } = useChartPressState({ x: 0, y: { highTmp: 0 } });
return (
// ...
<CartesianChart
// ...
chartPressState={state} // 👈 and pass it to our chart.
>
{/* ... */}
</CartesianChart>
// ...
);
}
// ...
Then we'll create a ToolTip component that uses some Reanimated SharedValues from our state variable.
import type { SharedValue } from "react-native-reanimated";
// ...
function ToolTip({ x, y }: { x: SharedValue<number>; y: SharedValue<number> }) {
return <Circle cx={x} cy={y} r={8} color="black" />;
}
And we'll conditionally show an instance of this component when the chart press is active:
// ...
import { /*...*/ useChartPressState } from "victory-native";
function MyChart() {
// ...
const { state, isActive } = useChartPressState({ x: 0, y: { highTmp: 0 } });
return (
// ...
<CartesianChart
// ...
chartPressState={state}
>
{
(/*...*/) => (
<>
{/* 👇 Conditionally show our tooltip and pass values. */}
{isActive ? (
<ToolTip x={state.x.position} y={state.y.highTmp.position} />
) : null}
</>
)
}
</CartesianChart>
// ...
);
}
// ...
With this in place, we have a rather simple tooltip UI:
Putting this all together, we have something like the following:
import * as React from "react";
import { View } from "react-native";
import { CartesianChart, Line, useChartPressState } from "victory-native";
import { Circle, useFont } from "react-native-skia";
import type { SharedValue } from "react-native-reanimated";
import inter from "../../assets/inter-medium.ttf"; // Wherever your font actually lives
function MyChart() {
const font = useFont(inter, 12);
const { state, isActive } = useChartPressState({ x: 0, y: { highTmp: 0 } });
return (
<View style={{ height: 300 }}>
<CartesianChart
data={DATA}
xKey="day"
yKeys={["highTmp"]}
axisOptions={{
font,
}}
chartPressState={state}
>
{({ points }) => (
<>
<Line points={points.highTmp} color="red" strokeWidth={3} />
{isActive && (
<ToolTip x={state.x.position} y={state.y.highTmp.position} />
)}
</>
)}
</CartesianChart>
</View>
);
}
function ToolTip({ x, y }: { x: SharedValue<number>; y: SharedValue<number> }) {
return <Circle cx={x} cy={y} r={8} color="black" />;
}
const DATA = Array.from({ length: 31 }, (_, i) => ({
day: i,
highTmp: 40 + 30 * Math.random(),
}));