Shipnative
ShipnativeShipnative
Sign in
GuideAugust 2026 · 8 min read

React Native Charts: Which Library, and How

Fitness apps, budget apps, habit trackers, dashboards — sooner or later the product needs a chart, and the first search sends you to Chart.js, which does not work here. React Native has no canvas and no DOM, so charts are drawn with SVG or with Skia. This guide covers the four real options, working code for the two you will actually pick, and the three mistakes that turn a chart screen into the slowest part of an app.

The four options

LibraryRenders withExpo GoStrengthTrade-off
react-native-gifted-chartsreact-native-svg✅ YesFastest to a good-looking chartHeavy on very large datasets
Victory NativeSkia + Reanimated❌ Dev buildGestures, tooltips, big dataMore setup, more concepts
react-native-chart-kitreact-native-svg✅ YesVery simple APISlow-moving, limited styling
Raw Skia / SVGYou⚠️ DependsAnything you can drawYou own axes, scales, labels

The honest decision rule is short. If your chart is a summary someone glances at — this week’s workouts, this month’s spending, weight over 90 days — take gifted-charts and move on with your day. If the chart is the product, with scrubbing, tooltips, and thousands of points, take Victory Native and accept the development build.

And the thing not on the list: rendering a web charting library inside a WebView. It works, it demos fine, and it costs you scroll performance, theme consistency, and the ability to style anything the way the rest of your app looks. Avoid it unless you are embedding a chart you genuinely cannot rebuild.

The common case: gifted-charts

npx expo install react-native-gifted-charts react-native-svg

Install react-native-svg through expo install rather than npm so the native version matches your SDK — a mismatch there is one of the more confusing red-screen errors in React Native.

A weekly bar chart, complete:

import { useMemo } from 'react';
import { Dimensions, StyleSheet, Text, View } from 'react-native';
import { BarChart } from 'react-native-gifted-charts';

const WIDTH = Dimensions.get('window').width;

export default function WeeklyActivity({ sessions }) {
  // aggregate raw rows into 7 buckets — never hand the chart raw data
  const data = useMemo(() => {
    const days = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];
    const counts = new Array(7).fill(0);
    for (const s of sessions) counts[dayIndex(s.completedAt)] += 1;

    return counts.map((value, i) => ({
      value,
      label: days[i],
      frontColor: value > 0 ? '#fb923c' : '#2a2a2a',
    }));
  }, [sessions]);

  return (
    <View style={styles.card}>
      <Text style={styles.title}>This week</Text>
      <BarChart
        data={data}
        width={WIDTH - 88}
        height={180}
        barWidth={22}
        barBorderRadius={6}
        spacing={16}
        noOfSections={3}
        yAxisThickness={0}
        xAxisThickness={0}
        yAxisTextStyle={{ color: '#8a8a8a', fontSize: 11 }}
        xAxisLabelTextStyle={{ color: '#8a8a8a', fontSize: 11 }}
        rulesColor="rgba(255,255,255,0.06)"
        isAnimated
      />
    </View>
  );
}

const styles = StyleSheet.create({
  card: { backgroundColor: '#141414', borderRadius: 16, padding: 20, margin: 16 },
  title: { color: '#fff', fontWeight: '700', fontSize: 16, marginBottom: 16 },
});

Most of those props exist to remove things: axis lines off, faint grid rules, small muted labels. A mobile chart competes with a 6-inch screen, and the default look of every charting library is a desktop chart with too much furniture. Strip it back and the data reads at a glance.

When the chart is the product: Victory Native

Victory Native renders through @shopify/react-native-skia with Reanimated for gestures, which is what makes smooth scrubbing over a long series possible. It needs a development build:

npx expo install victory-native @shopify/react-native-skia \
  react-native-reanimated react-native-gesture-handler
npx expo run:ios     # or run:android — Expo Go can't load Skia

The API is compositional — you provide the chart bounds and data keys, then draw the marks yourself:

import { CartesianChart, Line } from 'victory-native';

export default function WeightTrend({ points }) {
  return (
    <CartesianChart
      data={points}                 // [{ day: 1, kg: 82.4 }, …]
      xKey="day"
      yKeys={['kg']}
      axisOptions={{ lineColor: 'rgba(255,255,255,0.06)', labelColor: '#8a8a8a' }}
    >
      {({ points: p }) => (
        <Line points={p.kg} color="#fb923c" strokeWidth={3} curveType="natural" />
      )}
    </CartesianChart>
  );
}

That extra ceremony is the trade: you write more, and in exchange the chart stays at 60fps while a finger drags across it. If nobody is going to drag a finger across it, you did not need this.

Three mistakes that make charts feel slow

  1. Building the data array inline. data={sessions.map(…)} creates a new array on every parent render, so the chart rebuilds every SVG node every time — including when an unrelated piece of state changes. useMemo on the transform, and React.memoon the chart component, fixes the majority of “my charts screen is janky” reports.
  2. Rendering every point you have. A year of daily weigh-ins is 365 points on a screen about 350 points wide. Aggregate to weekly before rendering — it is faster and, more importantly, the trend becomes visible instead of a noisy hairline.
  3. Charts inside a scrolling list. Putting a chart in a FlatList row means it re-renders on scroll. Hoist it into ListHeaderComponent, or keep it on its own screen.

All three are versions of the same rule — render less, less often. The React Native performance fixes guide has the general form of it.

One chart usually beats four

The most common failure of a progress screen is not the library — it is four charts nobody reads. A tracking app generally needs one number the user cares about, one trend line for it, and one comparison against last period. Everything else is a settings screen for your analytics.

If you want to see how a chart reads on a phone before committing to a library, describe the screen — “a weekly bar chart of workouts completed and a line of body weight over 90 days” — and ShipNative builds it as real React Native, aggregation included, running on your device. Export the project and swap libraries later if you outgrow the first choice.

Frequently Asked Questions

What is the best charting library for React Native in 2026?

For most apps, react-native-gifted-charts — it renders with react-native-svg, works in Expo Go, and covers line, bar, pie, and area charts with very little setup. Choose Victory Native when you need interactive, gesture-driven charts over larger datasets, since it renders through Skia.

Can I use Chart.js or Recharts in React Native?

No. Both draw into an HTML canvas or the DOM, neither of which exists in React Native. You can render them inside a WebView, but you pay for it in scroll performance and theming pain — use a native charting library instead.

Do React Native charts work in Expo Go?

SVG-based libraries such as react-native-gifted-charts and react-native-chart-kit do, because react-native-svg is included in Expo Go. Skia-based libraries like Victory Native need @shopify/react-native-skia, so they require a development build.

Why does my chart make the whole screen scroll badly?

Usually because the chart re-renders on every parent render. Every SVG point is a component, so a 200-point line chart is hundreds of nodes rebuilt each time. Memoise the data array with useMemo, wrap the chart in React.memo, and downsample before you render — a phone-width chart cannot show more than a few hundred points anyway.

How many data points can a React Native chart handle?

SVG-based charts start to feel heavy somewhere in the low hundreds of points, especially on mid-range Android. Skia-based rendering pushes that considerably higher. If you have a year of daily readings, aggregate to weekly before rendering — it is both faster and easier to read.

Can an AI app builder add charts to my app?

Yes. Ask for a progress or analytics screen — "a weekly bar chart of workouts completed and a line chart of body weight over time" — and ShipNative picks a library, generates the screen and the aggregation, and previews it live so you can see whether the chart actually reads well on a phone.

→

React Native Performance: 10 Fixes

Charts are a render-cost problem — this is the broader toolkit.

Read guide →
→

Build a Workout Tracker App

A progress chart is the screen that makes tracking apps sticky.

See the plan →

Ship a real React Native app today

Describe, preview, and export Expo code — free to start.

Build with ShipNative →
ShipNative logoShipnative

Build mobile apps with AI. Describe, preview, and ship to iOS & Android in minutes.

Features

Text to App AIApp Generator from ScreenshotPRD to Mobile App

Tools

All free toolsApp Cost CalculatorApp Name GeneratorApp Store Keyword ToolReact Native Components

Blog

All blog postsHow to Build an App Without CodingBest AI Tools for Real Mobile AppsExpo EAS App Store ChecklistLovable, Cursor & v0 for MobileBest AI App Builders in 2026React Native AI App Builder Guide

Legal

FAQTerms of ServicePrivacy Policy

© 2026 ShipNative. All rights reserved.