Articles · App ExamplesUpdated September 2026

Add charts to an app in an afternoon, then spend the week on the query underneath.

Install one charting library, hand it an array of objects, and a line chart is about fifteen lines of JSX. In React Native that library is Victory Native, and the drawing really does take an afternoon. The limit worth knowing before you start is that drawing was never the hard part. Producing a dense, ordered, pre-aggregated array of points, with the empty buckets filled in and the days cut in the reader's timezone, is the work, and it is the only half that gets harder as the app grows. If what you want is usage numbers about your own product rather than your user's data, mobile app analytics is a different job with different tools.

This page covers which chart shape each question asks for, what a chart library actually installs, how to get your data into the one shape every chart wants, and how to make the result readable on a screen 360 points wide.

See which shape fits your data

The short version

The library draws the chart, the query decides whether it is true.

Two separate jobs hide behind a request to add charts to an app. One is rendering, where a package walks your array and paints paths on a canvas. The other is producing that array: grouping rows into buckets, filling the buckets nobody wrote to, and agreeing what a day means. The first job is a package install. The second is a schema decision you will live with.

So settle the question the chart answers before choosing anything else. Most of the time it is one measure over time, which is a line. A useful amount of the time the honest answer is a large number, a small label and no chart at all.

Pick the shape before you pick the library

A chart is a sentence about a comparison, and the comparison decides the shape. One measure over time is a line, with an area under it only when the volume itself means something. A handful of named things ranked against each other is a horizontal bar, sorted longest first, because sideways bars leave room for long labels and vertical ones cut them off. Two parts of a whole are two percentages in text. Four or more parts of a whole are a stacked bar, not a pie, because nobody reads angles.

Point count decides whether the chart earns its space at all. Under about seven values, a list of rows with the numbers printed on them is quicker to read and quicker to build. Over a few hundred, the question stops being which library and becomes what you aggregate before anything reaches the phone. The middle is where charts belong.

Graphs in a mobile app also fight a constraint a browser dashboard never has: roughly 360 points of width, held in one hand. A title, a legend, a y axis, an x axis and six series do not fit. One series, the last value labelled directly on the line, and a readout that follows a drag is usually the entire design. Everything you remove makes the remaining thing easier to read.

Try it

Which chart shape the question asks for

Pick what you are showing, then say how many points land on one screen.

Line, or area if the volume underneath means something

X is the bucket, Y is the measure. Label the last point on the line and the legend disappears. That is the range where a chart earns its space. One series, one axis label, and the value under the finger.

What a chart library actually installs

For a chart library React Native can genuinely use, Victory Native is the one worth naming, and its documentation is blunt about the cost. You install the peer dependencies first, React Native Reanimated, React Native Gesture Handler and React Native Skia, then add the Reanimated Babel plugin to your Babel config, and only then install victory-native itself. The introduction lists the same set as what it runs on, with a little D3 underneath for the scales and paths.

That list is the true install cost, and three of the four are native modules. This is not a package you drop into a JavaScript-only project and forget about. Before you plan around it, check whether your current build already carries Skia, Reanimated and Gesture Handler, because if it does not, you are changing how the app is built as well as adding a chart. Budget an hour for the install going wrong before you budget any time for the chart.

The reason the library was rewritten is itself useful when you are choosing. Victory Native XL moved off React Native SVG because SVG was not designed to have a large number of nodes updated dynamically, which the maintainers say made charts almost useless on Android once you added user interaction to a dataset of any real size. If your chart is small and static, plain SVG is still a perfectly good answer. If it pans, zooms or tracks a finger, that history is telling you which way to go, and it is the same trade that sits under most decisions about app performance.

What you get for it: line, area, bar, scatter and candlestick paths on a Cartesian chart, pie and donut on a polar one, plus animated paths and pan and zoom. That covers every chart a normal product needs. If your requirement falls outside that list, take another look at the requirement before you go looking for a second library.

Victory Native, Getting Started and installation

Every chart wants the same shape and your database does not have it

A chart component takes an array of objects, one per point, each carrying the x key and the y keys you named. That is the whole contract. Everything difficult happens before that array exists, and none of it is the library's problem.

Aggregate on the server, not on the phone. Pulling forty thousand rows down so the device can group them by day is how a data visualisation app ends up freezing for two seconds every time the screen opens. One grouped query that returns thirty rows is faster, cheaper on the connection and far easier to cache. The phone should receive points, not raw history.

Fill the gaps yourself. A day with no rows returns no row, and a chart will happily draw a straight line straight across the hole as though the week were smooth. Generate the full range of buckets first, join your results onto it, and put something explicit in every empty one. Decide whether that something is a zero or a null, because a day with no sales and a day with no data are different claims.

Bucket in the reader's timezone, not the server's. If the query groups by UTC day and the reader is in Auckland, part of their Monday lands on Sunday and the chart quietly stops agreeing with every other number in the app. This is the point where a chart turns into a schema question rather than a UI one, which puts it in the territory of mobile app database design.

Drawn is not the same as readable

Charts fail accessibility the same two ways every time, and both have names. Use of Color, a Level A criterion in WCAG 2.2, says colour is not used as the only visual means of conveying information or distinguishing a visual element. Two series in red and green with a colour-only legend fails it outright. Label the lines where they end, or vary the dash pattern, or do both and delete the legend.

Non-text Contrast, at Level AA, asks for a contrast ratio of at least 3 to 1 against adjacent colours for the parts of a graphic required to understand the content. That is the line itself, the bars, and any axis label the reader has to read. Pale grey on white is the default in a lot of chart themes and it does not clear that bar.

Then there is the thing no criterion will force on you: a chart is silent to a screen reader unless you give it a text alternative, and the fastest version of that fix helps everyone. Put the number in text beside the picture. Up 12 percent this week, printed above the sparkline, serves the screen reader, the person glancing at it on a train and the person holding the phone in sunlight.

Touch is the last one. A tooltip that appears on hover does not exist on a phone, so a chart nobody can interrogate is a decoration. If a single point has to be inspectable, make the whole plot respond to a drag with a readout pinned above it. That is precisely what the gesture library got installed for, so you may as well use it.

W3C, WCAG 2.2 Success Criterion 1.4.1 Use of Color

What each way of showing a number costs you

How you show itWhat it installsHandles many pointsPan, zoom and tapWhen it is the right answer
A number in large textnothingNoNoone measure, one glance
A list of rows with valuesnothingup to about 20Noa short ranking
Sparkline drawn with SVGone native packagea few hundredNoa trend beside a number
A Victory Native chartthree native peersYesYesthe normal case
A web chart in a WebViewa WebView and a bundled pageYesinside the web pageyou already own the web chart

Building the screen into an app you own

The build is small once the three questions above are answered. A chart screen is a query, a loading state, an empty state and about fifteen lines of chart. The empty state is the one everybody skips, and then the first person to open the app on day one sees an axis with nothing on it and assumes the feature is broken. Write that state before you write the chart.

Newly is an AI app builder. You describe the screen you want, it writes a real React Native and Expo project you own, runs it on a cloud iPhone or Android simulator while it builds, and ships to TestFlight and to Google Play internal testing. It is $25 a month and there is no free plan. The code stays yours either way: take it as a ZIP from Settings, or turn on the two-way GitHub sync from the Deploy tab and add whatever charting package you prefer by hand.

This page stops at the chart component on purpose. If you have not yet settled where the numbers come from, settle that first, because a chart is only a view of a table and the table is the decision that lasts.

Questions people ask about adding charts

Victory Native is the one to try first. Its documentation tells you to install React Native Reanimated, React Native Gesture Handler and React Native Skia as peer dependencies, add the Reanimated Babel plugin, then install victory-native. It draws line, area, bar, scatter and candlestick charts, plus pie and donut, with pan and zoom available.

Describe the one chart your app actually needs

Write down the question it answers and the query that returns one row per bucket, then build the screen, the empty state and the readout around those two things.

Start building