Victory Native vs React Native Chart Kit vs ECharts: Mobile Charts 2026
Victory Native vs React Native Chart Kit vs ECharts: Mobile Charts 2026
TL;DR
Data visualization on mobile is harder than web — no SVG in the native renderer, performance constraints on 60fps animations, and touch interactions that feel native. Victory Native XL (the rewritten version using React Native Skia) renders charts directly on the GPU via Skia canvas — smooth 60fps animations, declarative API, and full TypeScript types; it's the modern choice for performant React Native charts. React Native Chart Kit is the pragmatic option — uses SVG via react-native-svg, covers the most common chart types with minimal configuration, and has been the community default for years despite limited customization. Apache ECharts for React Native brings the full power of the ECharts ecosystem — 20+ chart types, rich interactions, WebView-based rendering; best when you need advanced chart types or are already using ECharts on web. For performant, customizable charts with Skia: Victory Native XL. For quick standard charts with SVG: React Native Chart Kit. For advanced chart types ported from a web ECharts implementation: Apache ECharts.
Key Takeaways
- Victory Native XL uses React Native Skia — GPU-accelerated canvas, not SVG
- React Native Chart Kit uses SVG — via
react-native-svg, more compatible - Apache ECharts uses WebView — full web ECharts in a WebView; most chart variety
- Victory Native XL supports Reanimated — gesture-driven interactions (pan, zoom)
- React Native Chart Kit: no live updates — static charts, no built-in animation
- ECharts React Native: 20+ chart types — map, sankey, sunburst, candlestick, etc.
- Victory Native XL is a complete rewrite — not backward-compatible with Victory Native v36
Chart Type Coverage
Bar chart → All three ✅
Line chart → All three ✅
Pie / Donut → All three ✅
Area chart → Victory Native XL, RN Chart Kit ✅
Scatter plot → Victory Native XL, ECharts ✅
Candlestick → ECharts ✅
Heatmap → ECharts ✅
Sankey diagram → ECharts ✅
Radar chart → ECharts, Victory Native XL ✅
Map / Geo → ECharts ✅
Progress ring → Victory Native XL ✅
Sparkline → Victory Native XL ✅
Victory Native XL: Skia-Powered Charts
Victory Native XL (v40+) is a complete rewrite of Victory Native using React Native Skia for direct GPU canvas rendering. It supports gesture-driven interactions via react-native-gesture-handler and react-native-reanimated.
Installation
npm install victory-native
# Required peer dependencies:
npm install react-native-skia react-native-reanimated react-native-gesture-handler
npx pod-install # iOS
Line Chart
import { CartesianChart, Line, useChartPressState } from "victory-native";
import { Circle, useFont } from "@shopify/react-native-skia";
import { useSharedValue } from "react-native-reanimated";
const data = [
{ day: "Mon", revenue: 1200 },
{ day: "Tue", revenue: 1800 },
{ day: "Wed", revenue: 1500 },
{ day: "Thu", revenue: 2100 },
{ day: "Fri", revenue: 2400 },
{ day: "Sat", revenue: 1900 },
{ day: "Sun", revenue: 800 },
];
function RevenueChart() {
const font = useFont(require("../assets/fonts/Inter-Regular.ttf"), 12);
const { state, isActive } = useChartPressState({ x: "day", y: { revenue: 0 } });
return (
<CartesianChart
data={data}
xKey="day"
yKeys={["revenue"]}
axisOptions={{
font,
formatYLabel: (value) => `$${value.toLocaleString()}`,
labelColor: "#666",
lineColor: "#e0e0e0",
}}
chartPressState={state}
>
{({ points }) => (
<>
<Line
points={points.revenue}
color="#3b82f6"
strokeWidth={2}
animate={{ type: "spring" }}
/>
{isActive && (
<Circle
cx={state.x.position}
cy={state.y.revenue.position}
r={8}
color="#3b82f6"
/>
)}
</>
)}
</CartesianChart>
);
}
Bar Chart
import { CartesianChart, Bar } from "victory-native";
function SalesBarChart() {
return (
<CartesianChart
data={data}
xKey="day"
yKeys={["revenue"]}
domainPadding={{ left: 20, right: 20, top: 20 }}
>
{({ points, chartBounds }) => (
<Bar
chartBounds={chartBounds}
points={points.revenue}
color="#3b82f6"
roundedCorners={{ topLeft: 4, topRight: 4 }}
animate={{ type: "spring", duration: 300 }}
/>
)}
</CartesianChart>
);
}
Pie / Donut Chart
import { PieChart } from "victory-native";
const pieData = [
{ label: "Direct", value: 40, color: "#3b82f6" },
{ label: "Organic", value: 25, color: "#10b981" },
{ label: "Paid", value: 20, color: "#f59e0b" },
{ label: "Referral", value: 15, color: "#ef4444" },
];
function TrafficSourceChart() {
return (
<PieChart
data={pieData}
labelKey="label"
valueKey="value"
colorKey="color"
outerRadius="80%"
innerRadius="50%" // Donut chart
animate={{ type: "spring" }}
/>
);
}
Interactive Tooltip
import { CartesianChart, Line } from "victory-native";
import { useChartPressState } from "victory-native";
import Animated, { useAnimatedStyle, useDerivedValue } from "react-native-reanimated";
function InteractiveChart() {
const { state, isActive } = useChartPressState({ x: "day", y: { revenue: 0 } });
const tooltipLabel = useDerivedValue(() =>
isActive.value
? `${state.x.value.value}: $${state.y.revenue.value.value.toFixed(0)}`
: ""
);
return (
<View>
{/* Tooltip */}
<Animated.Text style={tooltipStyle}>{tooltipLabel}</Animated.Text>
<CartesianChart
data={data}
xKey="day"
yKeys={["revenue"]}
chartPressState={state}
style={{ height: 250 }}
>
{({ points }) => <Line points={points.revenue} color="#3b82f6" strokeWidth={2} />}
</CartesianChart>
</View>
);
}
React Native Chart Kit: SVG Charts
React Native Chart Kit is the long-standing community choice for standard charts via SVG — straightforward API, covers most use cases, with react-native-svg under the hood.
Installation
npm install react-native-chart-kit react-native-svg
npx pod-install # iOS
Line Chart
import { LineChart } from "react-native-chart-kit";
import { Dimensions } from "react-native";
const screenWidth = Dimensions.get("window").width;
const chartConfig = {
backgroundColor: "#ffffff",
backgroundGradientFrom: "#ffffff",
backgroundGradientTo: "#ffffff",
decimalPlaces: 0,
color: (opacity = 1) => `rgba(59, 130, 246, ${opacity})`,
labelColor: (opacity = 1) => `rgba(100, 116, 139, ${opacity})`,
strokeWidth: 2,
propsForDots: {
r: "4",
strokeWidth: "2",
stroke: "#3b82f6",
},
};
function RevenueLineChart() {
return (
<LineChart
data={{
labels: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
datasets: [
{
data: [1200, 1800, 1500, 2100, 2400, 1900, 800],
color: (opacity = 1) => `rgba(59, 130, 246, ${opacity})`,
strokeWidth: 2,
},
],
}}
width={screenWidth - 32}
height={220}
chartConfig={chartConfig}
bezier // Smooth curves
style={{ borderRadius: 12 }}
formatYLabel={(value) => `$${parseInt(value).toLocaleString()}`}
onDataPointClick={({ value, index }) => {
console.log(`Tapped: ${value} at index ${index}`);
}}
/>
);
}
Bar and Pie Charts
import { BarChart, PieChart, ProgressChart } from "react-native-chart-kit";
function SalesBarChart() {
return (
<BarChart
data={{
labels: ["Mon", "Tue", "Wed", "Thu", "Fri"],
datasets: [{ data: [1200, 1800, 1500, 2100, 2400] }],
}}
width={screenWidth - 32}
height={220}
chartConfig={chartConfig}
yAxisLabel="$"
yAxisSuffix=""
showValuesOnTopOfBars
/>
);
}
function TrafficPieChart() {
return (
<PieChart
data={[
{ name: "Direct", population: 40, color: "#3b82f6", legendFontColor: "#666", legendFontSize: 12 },
{ name: "Organic", population: 25, color: "#10b981", legendFontColor: "#666", legendFontSize: 12 },
{ name: "Paid", population: 20, color: "#f59e0b", legendFontColor: "#666", legendFontSize: 12 },
]}
width={screenWidth - 32}
height={200}
chartConfig={chartConfig}
accessor="population"
backgroundColor="transparent"
paddingLeft="10"
/>
);
}
Apache ECharts for React Native: WebView Charts
ECharts for React Native wraps Apache ECharts in a WebView — full access to ECharts' 20+ chart types, themes, and interactions.
Installation
npm install @wuba/react-native-echarts react-native-webview react-native-svg
npx pod-install # iOS
Line Chart with ECharts
import { useRef, useState, useEffect } from "react";
import { SkiaChart, SVGRenderer } from "@wuba/react-native-echarts";
import * as echarts from "echarts/core";
import { LineChart } from "echarts/charts";
import { GridComponent, TooltipComponent, LegendComponent } from "echarts/components";
// Register required components
echarts.use([SVGRenderer, LineChart, GridComponent, TooltipComponent, LegendComponent]);
function EChartsLineChart() {
const chartRef = useRef(null);
useEffect(() => {
const chart = echarts.init(chartRef.current, "light", {
renderer: "svg",
width: 350,
height: 250,
});
chart.setOption({
tooltip: {
trigger: "axis",
formatter: (params: any[]) => {
return `${params[0].axisValue}: $${params[0].value.toLocaleString()}`;
},
},
xAxis: {
type: "category",
data: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
},
yAxis: {
type: "value",
axisLabel: { formatter: (val: number) => `$${val.toLocaleString()}` },
},
series: [
{
data: [1200, 1800, 1500, 2100, 2400, 1900, 800],
type: "line",
smooth: true,
lineStyle: { width: 2, color: "#3b82f6" },
areaStyle: { color: "rgba(59, 130, 246, 0.1)" },
},
],
});
return () => chart.dispose();
}, []);
return <SkiaChart ref={chartRef} />;
}
Advanced: Candlestick Chart (Not available in other libraries)
import { CandlestickChart } from "echarts/charts";
echarts.use([CandlestickChart]);
function StockChart() {
const chartRef = useRef(null);
useEffect(() => {
const chart = echarts.init(chartRef.current, "light", {
renderer: "svg",
width: 350,
height: 300,
});
// [open, close, low, high]
const stockData = [
[150, 155, 148, 157],
[155, 152, 149, 158],
[152, 160, 151, 162],
[160, 158, 155, 163],
[158, 165, 156, 167],
];
chart.setOption({
xAxis: {
data: ["Mon", "Tue", "Wed", "Thu", "Fri"],
},
yAxis: { scale: true },
series: [
{
type: "candlestick",
data: stockData,
itemStyle: {
color: "#10b981", // Bullish
color0: "#ef4444", // Bearish
borderColor: "#10b981",
borderColor0: "#ef4444",
},
},
],
});
return () => chart.dispose();
}, []);
return <SkiaChart ref={chartRef} />;
}
Feature Comparison
| Feature | Victory Native XL | RN Chart Kit | ECharts RN |
|---|---|---|---|
| Renderer | Skia (GPU canvas) | SVG | WebView/SVG |
| Performance | ✅ Excellent | ✅ Good | ⚠️ WebView overhead |
| Chart types | 8 | 8 | 20+ |
| Gesture/zoom | ✅ Reanimated | ❌ | ✅ |
| Animations | ✅ Spring | Limited | ✅ Rich |
| Candlestick | ❌ | ❌ | ✅ |
| Heatmap | ❌ | ❌ | ✅ |
| Sankey/Flow | ❌ | ❌ | ✅ |
| TypeScript | ✅ Excellent | ✅ Good | ✅ Good |
| Bundle size | Medium | Small | Large (ECharts) |
| Custom drawing | ✅ Skia canvas | ❌ | ❌ |
| GitHub stars | 1.6k | 2.5k | 4k |
When to Use Each
Choose Victory Native XL if:
- Performance is critical — 60fps animations with gesture-driven interactions (pan, zoom, scrub)
- Skia canvas gives access to custom drawing alongside charts
- Standard chart types (line, bar, area, pie, scatter) cover your needs
- TypeScript-first, modern React Native stack (Skia + Reanimated + Gesture Handler)
Choose React Native Chart Kit if:
- Quick standard charts without performance requirements
- Simpler setup — just
react-native-svgas a dependency - Community-familiar API that's been stable for years
- No need for gesture interactions or animation beyond basic entrance animations
Choose ECharts React Native if:
- Advanced chart types not available in other libraries (candlestick, sankey, heatmap, geo maps)
- You're porting a web ECharts implementation to React Native
- Rich built-in interactions (click to filter, drill-down, zoom) matter
- WebView overhead is acceptable for your use case
Methodology
Data sourced from official Victory Native documentation (commerce.nearform.com/open-source/victory-native), React Native Chart Kit GitHub repository, Apache ECharts for React Native documentation (wuba.github.io/react-native-echarts), npm download statistics as of February 2026, GitHub star counts as of February 2026, and community discussions from the React Native Discord and r/reactnative.
Related: FlashList vs FlatList vs LegendList for the list rendering performance that often houses chart data, or React Native Reanimated vs Moti vs Skia for the animation libraries that Victory Native XL is built on.