RN: Victory Native (XL) for standard charts; react-native-skia when you need custom/realtime rendering. Web: Recharts (batteries-included) or visx (low-level D3). Skia-backed chart stacks stay on @shopify/react-native-skia (≤2.14) until Victory Native XL / livechart repoint to the renamed react-native-skia (RB-E-ANIMATION).
realtime/finance RN charts → Victory Native XL, else react-native-graph for scrubbing line charts, else react-native-livechart (all Skia-based; the latter two newer/niche)
RN app on Skia below 2.6.0 or Reanimated below 3.19.1 → Victory Native 41.x (pinned; 42 raises both floors)
RN team wanting the quickest declarative adoption without a Skia dependency → react-native-gifted-charts (SVG-rendered)
fully custom web viz → visx
quick standard web charts → Recharts
web charts from the TanStack stack with a 1.0 API contract → TanStack Charts (new; no adoption signal yet; RN support experimental)
existing Chart.js web code → Chart.js (keep it; this entry does not grade it against Recharts/visx)
heavy Skia/Reanimated perf → react-native-best-practices (owns render-perf depth)
Low confidence — fast-moving or lightly-vetted domain: treat the pick as a vetted lead and prototype before committing.
Options & tradeoffs
the field considered — and why each one isn’t the default here
option
tradeoff
evidence
Victory Native (XL)
RN; Skia-backed (peers @shopify/react-native-skia + Reanimated + Gesture Handler); mature, broad chart types. 42.0.1 (2026-08-31, verified vs npm 2026-09-24) is a floor-raise major: Skia >=2.6.0 <3.0.0 and Reanimated >=3.19.1; on older Skia/Reanimated stay on 41.x. See note: VICTORY NATIVE 42
521k/wk · ships in 2/34
react-native-gifted-charts
RN; declarative, quick to adopt; renders through react-native-svg, not Skia (peer verified vs npm 2026-09-24; latest 1.4.78, 2026-08-10)
286k/wk
react-native-skia (build-your-own)
RN; max control + perf, more code. Now published as `react-native-skia` (3.x Graphite; v2 line as react-native-skia@2) — but Victory Native XL and react-native-livechart still peer on @shopify/react-native-skia, so a chart stack stays on the old name for now. See note: SKIA STEWARDSHIP
RN; Skia-based LINE graphs with gesture scrubbing; rebooted at v1.2 (2026-04-15) onto current Skia APIs after ~2y dormancy and has shipped since (1.4.0, 2026-08-24, verified vs npm + releases 2026-09-24) — line-focused, check it covers your chart types
23k/wk
Recharts / visx / Chart.js
web; visx = low-level D3 primitives (4.0.0), Recharts = batteries-included (3.10.1), both current (verified vs npm 2026-09-24). Chart.js is carried for detection and not graded against them. The legacy web `victory` package is not one of these — it is dormant, see note: VICTORY (WEB)
71.3M/wk · ships in 5/34
TanStack Charts (NEW, 1.0)
web (and experimental RN): marks + scales + axes (grammar-of-graphics, Observable Plot lineage) from the org behind Query/Table/Router; 1.0.0 (2026-10-03, verified vs npm + the v1.0.0 release) is a compatibility contract for the documented public API; SVG by default, Canvas as a separate renderer; React via @tanstack/react-charts 1.0.0. React Native 'remains experimental' (optional peers react-native ^0.86 + react-native-svg 15.15.4+). No adoption signal yet. See note: TANSTACK CHARTS
The durable axis is the RENDERER, not the chart menu. On React Native the picks draw through Skia on the GPU: Victory Native XL for standard charts, raw react-native-skia when you need custom/realtime rendering, so graduating from one to the other changes how much chart you hand-write, not what draws the pixels. On the web the division is D3 for math/layout while React owns the DOM; Recharts (batteries-included) and visx (low-level primitives) differ only in altitude. The library picks are reasonable defaults but lightly vetted, which is why confidence is low; ignore react-native-livechart's satirical "degen mode" framing — not a selection axis.
VICTORY NATIVE 42 (42.0.0 2026-08-25, 42.0.1 2026-08-31; verified vs npm + GitHub): a FLOOR-RAISE major, not a feature release — minimum @shopify/react-native-skia >=2.6.0 (chart paths migrated to the immutable PathBuilder API) and minimum Reanimated >=3.19.1 → on older Skia/Reanimated stay on 41.x.
SKIA STEWARDSHIP (2026-09-21, pointer — RB-E-ANIMATION owns this thread, its receipts and the tripwire): Shopify is leaving React Native, sponsors react-native-skia through the end of 2026, and its author forks the repo under a NEW NAME in the coming months, after which the Shopify repo is archived. Nothing is deprecated today (2.12.0 shipped 2026-09-16, after the announcement). The exposure here is broad rather than deep: Victory Native XL, react-native-graph and react-native-livechart all render THROUGH Skia, so a rename propagates to their peer ranges, not just to your own dependency list → pin across the transition window. 2026-10-08: the rename LANDED — `react-native-skia` 3.x (and @2 for the v2 line) — while victory-native 42.0.1 still peers @shopify/react-native-skia >=2.6.0 <3.0.0 and react-native-livechart 4.26.0 peers @shopify/react-native-skia >=2.6.0 (both verified vs npm), so those stacks hold the old name; react-native-graph 1.4.0 declares no Skia peer at all.
DEFAULT CHALLENGED (2026-08-18, verified vs the npm API and GitHub): react-native-gifted-charts ships weekly (1.4.78, 2026-08-10) and had more stars (1,362 vs 1,210), so should it take the RN default? No, on both axes this entry claims. DOWNLOADS: victory-native 381,672/wk vs gifted-charts 147,977/wk (2.6× the other way). SUBSTRATE: victory-native peers on @shopify/react-native-skia + Reanimated + Gesture Handler, gifted-charts on react-native-svg, so "Skia-backed for standard charts, raw Skia for custom/realtime" is a real rendering difference, not branding.
VICTORY (WEB) IS DORMANT (2026-08-18, verified vs npm + GitHub; npm re-checked 2026-09-24): npm 37.3.6 published 2025-01-14, repo last pushed 2025-12-19. Nothing here recommends it; its detect label says "dormant" because it shares the "victory" token with victory-native, which had made `react-brain signals` report a dormant web package as a stale recommended default.
D3 FRESHNESS (signals, 2026-07-10): d3's 2-year publish gap is maturity, not abandonment — it is the stable substrate under visx.
TANSTACK CHARTS LEAD (2026-09-10; 0.18.0 of 2026-09-10 verified vs npm + the v0.18.0 release 2026-09-24): @tanstack/charts is officially ALPHA (README badge and stability policy) and was called "ready to be field-tested" at 0.16 — a charting entrant from the org behind Query, Router, Table, Form and AI in this corpus; 0.18.0 adds renderer-neutral radial gradients with SVG and React Native fill support. NOT an option yet: alpha, no adoption signal; weigh it against the rows above at 1.0. 2026-10-08: 1.0.0 SHIPPED (2026-10-03, verified vs npm, the v1.0.0 release and Tanner Linsley's announcement): the release "establish[es] the TanStack Charts 1.0 compatibility contract for documented public APIs, extension protocols, framework support, and renderer behavior" and says "React Native remains experimental"; SVG is the default renderer with Canvas imported separately; no bundle figures were published. So it enters as a web option row, not the default: the stability contract is new, the adoption signal is still zero.
HISTORY: 2026-10-08 REOPENED: TanStack Charts 1.0 (web option row; RN experimental); the Skia rename landed and Victory Native XL / livechart still peer on the @shopify name. 2026-09-01 CORRECTED: the "Victory Native XL is slower-moving — watch it" caveat from the 2026-08-18 challenge retired; v42 shipped two months after it. 2026-08-18 CHALLENGED → WEAKENED: the RN default (Victory Native XL over gifted-charts) survived on downloads and substrate; the web `victory` package was reclassified from slow to dormant.
Canonical reading
Editorial annotations on why each piece matters — the articles themselves are the originals; read them there.
The argument that most directly challenges how this entry (and every library-selection entry) is framed, made concrete on charts. Wieruch spiked the same design-system chart set twice in an hour — once on D3's math primitives with React rendering the SVG, once on Recharts with an identical component API — and the primitive version matched the design exactly (entrance animations, crosshair tooltips, legend filtering) while the Recharts version reached 80% faster and then hit a wall: the last 20% needed custom SVG anyway, and its entrance animation froze in that React stack with no fix but disabling it. His frame is worth borrowing: a high-level library is PREPAID IMPLEMENTATION LABOR, bought with flexibility — a primitive maps a value to a pixel and has no opinion about what you draw, a framework owns rendering, animation lifecycle and tooltips and hands you config props to negotiate with, and the difference only shows up when your requirements leave the author's assumptions. The claim is not that libraries lost; it is that agentic coding moved the CROSSOVER POINT toward primitives, so requirements that used to sit safely on the library side (three charts matching a design system, a bespoke form flow, a custom data grid) now often sit on the other. He argues the other side himself, and those caveats are the load-bearing part: a team without an established agentic workflow cannot place this bet, because the old labor math still applies to them; commodity UI on a library's happy path should stay there; every line you own is a line you maintain, without a community surfacing edge cases; deep-accessibility widgets (combobox, date picker, focus-managed modal) encode years of screen-reader testing not worth regenerating; and genuinely hard stable problems — date arithmetic, color interpolation, schema validation, floating-element positioning — stay dependencies. His last caveat is the sharpest: the spike worked because he could JUDGE the output, and an agent collapses the cost of writing a layer, not the cost of understanding it.
The architecture of web React charting — use D3 for math/layout while React owns the DOM, and compose low-level primitives instead of opinionated chart components. First-principles framing that applies to visx, Recharts, and any D3+React stack.
How RN Skia renders graphics — incl. the canonical high-density line-chart-as-GPU-texture example, JSI, immutable display lists, a unified WebGPU backend. The rendering model under Victory Native XL and build-your-own Skia charts.
Depth (in-domain rules) is owned by the react-native-best-practices skill — this entry is selection breadth.
The full explanation
The reviewed long-form essay behind this entry — the why, not a how-to. Also on GitHub.
About charting & data visualization
Diataxis: Explanation. This page builds understanding of the charting decision — why
the durable axis is the renderer, not the chart catalogue. It is not a gallery tour and not
an API guide. The candidate list and one-line tradeoffs live in the index entry
RB-E-CHARTS; Skia/Reanimated render-performance depth is owned by the
react-native-best-practices skill. The entry's own confidence is low — its note says
the picks are reasonable defaults but lightly vetted — so read this as a map, then verify
against your chart-type needs.
The one distinction that organises everything: pick the renderer, not the chart menu
A chart is a list wearing math. Underneath every bar, line, and candlestick there is a list of
data points, a math/layout pass that turns data into geometry, and a renderer that draws
the geometry. The two readings the index entry leans on describe exactly this split, once per
platform:
Web: the visx architecture piece states the durable division of labor — D3 for
math/layout while React owns the DOM, composing low-level primitives instead of
opinionated chart components. That framing applies to visx, Recharts, and any D3+React
stack.
React Native: the Shopify graphics piece gives the render model under the RN picks —
Skia via JSI, immutable display lists, a unified WebGPU backend, with the canonical
example being a high-density line chart rendered as a GPU texture.
So the real decision is which renderer draws your geometry — the DOM/SVG on web, the GPU via
Skia on React Native — and how much of the math you want pre-packaged (batteries-included
components vs low-level primitives). The chart menu — does the library's gallery have a
donut? — is the least durable axis, because the math is a commodity (D3 on web) and the
renderer is what a high-density realtime series lives or dies by — which is exactly why the
canonical Skia example is a dense line chart rendered as a GPU texture.
The default, and why
RN: Victory Native (XL) for standard charts; react-native-skia when you need custom/realtime
rendering. Web: Recharts (batteries-included) or visx (low-level D3).
On React Native both halves of the default sit on the same renderer: Victory Native XL is
Skia-backed, mature, with broad chart types — and when its packaging runs out,
build-your-own on react-native-skia buys maximum control and performance at the cost of
more code. Graduating from one to the other changes how much chart you hand-write, not what
draws the pixels.
On web the two picks share the D3+React division of labor and differ only in altitude:
Recharts is batteries-included; visx is low-level D3 primitives for fully custom
visualization. Pick by how bespoke the viz is, not by gallery screenshots.
The specialised when-clause is realtime/finance on RN: stay Skia-based — Victory Native XL,
react-native-graph for scrubbing line charts, or react-native-livechart — with the
honest caveat, from the entry itself, that the latter two are newer/niche.
The landscape, and when each one wins
Victory Native (XL) — the RN standard-charts default: Skia-backed, mature, broad chart
types. One freshness fact matters when you audit it: the active Victory line is
victory-native XL (42.0.1, 2026-08-31, verified against npm 2026-09-24); the web victory
package is dormant (last publish 2025-01-14). Judge the family by the XL line. v42 is a
floor-raise major: it needs @shopify/react-native-skia >=2.6.0 and Reanimated >=3.19.1 — on
older versions stay on 41.x.
react-native-skia (build-your-own) — max control and max performance, more code. This is
the "custom/realtime rendering" escape hatch, and the Shopify piece is its physics textbook:
JSI, immutable display lists, WebGPU backend, line-chart-as-GPU-texture.
react-native-graph (Margelo) — Skia-based line graphs with gesture scrubbing. Its
history is a lesson in reading release pages: rebooted at v1.2 (2026-04) onto current Skia
APIs after roughly two years of dormancy, and it has kept shipping since (1.4.0, 2026-08-24). Line-focused — the entry's own instruction is to
check it covers your chart types before adopting.
react-native-livechart — Skia + Reanimated + Gesture Handler; realtime/finance focus with
crosshair scrubbing; newer and niche. The entry's note is explicit: ignore its satirical
"degen mode" framing — that is not a selection axis.
react-native-gifted-charts — declarative and quick to adopt. It renders through
react-native-svg, not Skia (its npm peer dependency), so it sits off the Skia axis: the pick
when adoption speed matters more than a GPU renderer.
Recharts / visx / Chart.js (web) — Recharts batteries-included, visx low-level D3
primitives; Chart.js is listed in the same web group without a graded tradeoff. Beneath visx
sits d3 itself, and its npm silhouette needs the same freshness literacy as Victory's:
d3's 2-year publish gap is maturity, not abandonment — it is the stable substrate under
visx.
Skia is changing hands (2026-09-21). Shopify is leaving React Native; react-native-skia's
author will fork it under a new package name and the Shopify repo will be archived. Victory
Native XL, react-native-graph and react-native-livechart all render through Skia, so the rename
reaches their peer ranges too — pin Skia-backed chart stacks across the transition
(RB-E-ANIMATION owns the thread).
Tradeoffs and failure modes to name out loud
Choosing from the chart menu. The gallery answers "can it draw a donut today"; the
renderer answers "will it still be smooth with real data and realtime updates." The entry's
when-clauses are renderer-shaped (realtime/finance → Skia-based), not gallery-shaped.
Adopting a scrubbing library, then needing a bar chart. react-native-graph is
line-focused by design — the entry literally says to check it covers your chart types. The
scrubbing demo is not a commitment to breadth.
Reading npm dates as health. Two opposite errors, both named in the entry's freshness
note: d3's 2-year gap is maturity, not abandonment; and the dormant web victory
package is not the active line — victory-native XL (42.0.1, 2026-08-31) is. Publish cadence
only means something relative to a library's role in the stack.
Dormancy that did matter. react-native-graph sat dormant for ~2 years before its
v1.2 (2026-04) reboot onto current Skia APIs — for Skia-adjacent libraries, "does it target
the current Skia era" is a real compatibility question, not paranoia.
Marketing noise as signal. react-native-livechart's satirical "degen mode" framing is
not a selection axis — evaluate the stack (Skia + Reanimated + Gesture Handler, crosshair
scrubbing) and the newer/niche maturity, not the bit.
Trusting this page too much. Confidence here is low by the entry's own admission: the
picks are reasonable defaults, lightly vetted. Verify chart-type coverage and freshness
against npm before committing.
How it interacts with the rest of the stack
Render performance (react-native-best-practices). The defer skill: heavy
Skia/Reanimated performance discipline lives there. This page owns which renderer and which
library; that skill owns keeping the frames.
Animation & gestures (RB-E-ANIMATION). The realtime RN options are built from the
animation stack's parts — react-native-livechart is explicitly Skia + Reanimated + Gesture
Handler, and gesture scrubbing is the headline feature of react-native-graph. Interactive
charts are animation surfaces.
SVG (RB-E-SVG). The web half of the renderer axis. The D3+React division — D3 for
math/layout, React owning the document — is the same architecture whether the primitives are
a chart library's or your own.
Lists (RB-E-LISTS). The "lists wearing math" lens is literal at high density: a
realtime series is list-scale data on a render budget, which is exactly why the canonical
Skia example is a high-density line chart as a GPU texture.
In one paragraph
Charts are lists wearing math: data, a math/layout pass, and a renderer — and the renderer is
the durable axis. On web, D3 does math/layout while React owns the DOM (Recharts
batteries-included, visx low-level primitives; d3's 2-year publish quiet is maturity, not
abandonment). On React Native the renderer is Skia on the GPU — JSI, immutable display
lists, a WebGPU backend, high-density line charts as GPU textures — under both the default
(Victory Native XL, 42.x active line) and the escape hatch (build-your-own
react-native-skia). Realtime/finance stays Skia-based via react-native-graph (line-focused,
rebooted v1.2 2026-04 after ~2y dormancy — check chart-type coverage) or
react-native-livechart (newer/niche; ignore the satirical framing). Pick by renderer and
altitude, verify the lightly-vetted specifics against npm, and take Skia/Reanimated
performance depth from react-native-best-practices.
See also: RB-E-SVG (the web renderer under D3+React stacks), RB-E-ANIMATION (Reanimated +
Gesture Handler, the substrate of scrubbing charts), RB-E-LISTS (high-density data on a
render budget). Performance depth: the react-native-best-practices skill. Background
reading: Airbnb's visx introduction (D3 for math, React for the document) and William
Candillon's RN graphics deep-dive (the Skia/WebGPU render model).