You probably don't need D3.js - here are the 20% of cases where it's irreplaceable
Most people reach for D3 when a simpler library would suffice. Here's when D3.js is truly irreplaceable, and what to use the rest of the time - including WebGPU, now Baseline.
Raw data is silent
A table of figures never tells a story on its own. Raw data is objective and mute; it's visualization that gives it a voice, revealing hidden trends, anomalies and unexpected correlations. After years of transforming complex datasets into visual narratives, I have a conviction that runs counter to the reflex of many developers: most of the time, when someone opens D3.js, they're using the wrong tool. Not because D3 is bad - it's the opposite, it's the most powerful tool in the field - but because its power pays off in complexity, and in eight cases out of ten a simpler library would have delivered the same result in a quarter of the time.
The real skill in datavisualization isn't knowing the D3 API by heart. It's knowing what question to ask the data, and what tool to call upon to answer it. So let's start there.
The question is not "how D3" but "do I need D3?
D3.js, version 7.9, remains the benchmark for custom visualizations. Entirely restructured into ES modules, the library is tree-shakeable: you import only the useful sub-modules from the thirty or so available - d3-scale, d3-shape, d3-selection, d3-transition, d3-geo, d3-hierarchy, d3-force, d3-zoom. But this power comes with a real learning curve, and producing it for a simple bar graph is a waste.
For most needs, the ecosystem offers a better fit. Here's how I decide.
| Tool | Type | Ideal for |
|---|---|---|
| Recharts | declarative React components | standard dashboards and graphs, fast |
| Observable Plot | graph grammar on D3 | exploration and prototyping in a few lines |
| Nivo | React on D3, advanced theming | neat turnkey visuals |
| visx (Airbnb) | low-level React primitives | fine control without rewriting everything in D3 |
| Tremor dashboards + native Tailwind product dashboards | ||
| D3.js (pure) | low-level, total control | truly bespoke visualization |
Observable Plot deserves a special mention: developed by the team behind D3, its mark-based API (Plot.barY, Plot.line, Plot.dot) automatically handles scales, axes and legends. It's become my default prototyping tool - I rough in Plot, and only switch to pure D3 if the end result demands it. None of these libraries replaces D3 for custom work, but together they cover around 80% of common use cases.
When D3 is irreplaceable - without coding spaghetti
The remaining 20% fully justify D3: a visualization whose form doesn't exist in any library, a novel interaction, a force layout or a particular geographical projection. The trap at this level is spaghetti code - D3 being low-level, it's easy to get everything mixed up. The rule that saved me: in the React context, D3 never touches the DOM. It does the math - scales, layouts, shape generators - and React does the rendering in JSX. This separation has become the consensus best practice.
jsx import { scaleLinear } from "d3-scale"; import { line } from "d3-shape";
function useLinePath(data, width, height) { const x = scaleLinear().domain([0, data.length - 1]).range([0, width]); const y = scaleLinear().domain([0, Math.max(...data)]).range([height, 0]); const path = line()((d, i) => [x(i), y(d)]); return path(data); }
// The component only renders - D3 did the calculation function Sparkline({ data, width = 240, height = 60 }) { const d = useLinePath(data, width, height); return ( <svg width={width} height={height} role="img" aria-label="Trend"> <path d={d} fill="none" stroke="currentColor" strokeWidth={2} /> </svg> ); }
I encapsulate scales and layouts in dedicated hooks (useScale, useLayout), and the component remains declarative. This retains the responsiveness of React and the mathematical power of D3, without sacrificing legibility.
## SVG, Canvas, WebGPU: the right engine for the right scale
The choice of rendering engine is not a detail, and this is where 2026 has really changed the game. Below around 1,000 elements, SVG is ideal: native interactivity, accessibility, easy debugging. Between 1000 and around 100,000, Canvas becomes necessary to keep rendering fluid - beyond that, Canvas 2D starts to stall. And that's where the news comes in: WebGPU became Baseline in January 2026, supported by all major browsers, with coverage of around 87% on desktop and 71% on mobile. In concrete terms, WebGPU renders clouds of more than 10 million points interactively, where Canvas 2D chokes on more than 100,000; demos like ChartGPU display a million points at 60 frames per second.
What this changes for me: I no longer treat high-volume rendering as an exotic problem reserved for cobbled-together WebGL. For a massive dataset - sensors, logs, dense geospatial - WebGPU is now a production option, not a gamble. The tipping threshold remains the same as before, but the ceiling has exploded.
## Animation as a narrative tool
Animation is not an embellishment, it's a storytelling tool. An animated transition between two states of a graph allows the brain to follow the transformation of data, instead of mentally comparing two frozen images. D3 offers a robust transition system via d3-transition, with automatic interpolation of SVG values, colors and paths. For more complex sequences, GSAP remains the benchmark for control and performance; in React, Framer Motion natively handles SVG with its motion.path component.
Scrollytelling is the most effective narrative technique for long-form graphics. I structure these visualizations like an article: a teaser that sets the context, sections that reveal the layers of data one by one, a conclusion that synthesizes the insight. Each scroll level triggers a transition that recontextualizes the graphic. And as with any animation, I respect prefers-reduced-motion: a movement that helps reading for most may be an obstacle for others.
## Accessibility is not optional
This is the most common blind spot in datavisualization. An SVG graphic should carry a role="img" and an aria-label that summarizes the key information. For interactive visualizations, I add aria-live regions that announce data changes to screen readers, and I systematically provide a fallback-structured data table - visually hidden but accessible - for those who can't interpret the graph. The choice of colors is equally important: I rely on palettes with sufficient contrast and distinguishable in case of color blindness, and I never base information on color alone - always color plus shape, or color plus direct label.
Basically, datavisualization is where design, development and journalism meet. Mastering D3.js is only the technical dimension, and often the least important. Knowing when not to use it, choosing the right rendering engine, and communicating the truth in a clear, honest and accessible way: that's the real job.
15 CSS micro-interactions without a single line of JavaScript (which required a lib yesterday)
The underline that slides, the map that flips to 3D, the animated input without display: none cobbled together: 15 micro-interactions in pure CSS, at 60 fps, without a single line of JavaScript.
From Figma to React component in 5 steps - and half the glue from before is no longer needed
The token→component pipeline that everyone copies is half out of date. Since Tailwind v4 and the Design Tokens stable spec, here are the 5 steps that really matter when moving from Figma to React.
Generate 50 banners in one go with Node.js - but stop writing your SVG text by hand
A Node.js pipeline produces fifty variations of social visuals in less than a minute. Sharp for compositing and optimization, Satori for text - and everything else you don't want to code by hand.