mrkeyoor.com_
Wed 23 Sept 00:37 UTC
npmWeb Frontendupdated 22 Sept 2026

@visx/curve review

@visx/curve 4.0.0 re-exports 18 D3 curve factories through @visx/vendor. Pass one to the curve prop of @visx/shape's LinePath or another compatible path generator to choose linear, stepped, monotone, basis, bundle, cardinal, Catmull-Rom, or natural interpolation. Version 4 adds package-root exports for require and import, strict ESM output, modern browser targets, and D3 shape 3 underneath. The package contains no React component, scale, axis, tooltip, animation, or accessibility layer. Our full browser import measured 14.7 KB minified and 2.5 KB gzipped.

Verdict

@visx/curve 4.0.0 installed in 4.4 seconds, used 6 MB across 28 packages, bundled to 2.5 KB gzipped, and returned 0 audit findings in our sandbox. Add it beside @visx/shape for visx-aligned D3 interpolation; install d3-shape directly outside visx, or choose a full chart library when curves are only one missing piece.

We installed it

Lab card: what happened when we installed @visx/curveScreenshot of @visx/curve documentation
Install✓ · 4.4s28 packages on disk · 6 MB
ImportESM import works · require() works · CommonJS package with exports map
Browser2.5 KBgzipped (14.7 KB minified), bundled with esbuild
TypesTypeScript types bundled
Known vulns00 critical · 0 high · 0 moderate · 0 low (npm audit)

Answers from our run

Does @visx/curve install cleanly?

Yes. In a fresh container with an empty cache, npm install @visx/curve finished in 4 seconds, leaving 28 packages and 6 MB on disk. npm audit reported no known vulnerabilities.

How much does @visx/curve add to a browser bundle?

2.5 KB gzipped (14.7 KB minified) when the whole package is bundled for the browser with esbuild. Importing only part of it is usually smaller.

Does @visx/curve work with both ESM and CommonJS?

Yes. Both import '@visx/curve' and require('@visx/curve') worked in Node 22 in our run. The package is published as CommonJS with an exports map.

Does @visx/curve include TypeScript types?

Yes, type declarations ship inside the package, so no @types install is needed.

@visx/curve or d3-shape: which should you use?

d3-shape: Use it directly outside visx or when the same module should also provide line, area, arc, pie, stack, and symbol generators. @visx/curve 4.0.0 installed in 4.4 seconds, used 6 MB across 28 packages, bundled to 2.5 KB gzipped, and returned 0 audit findings in our sandbox.

When should you not use @visx/curve?

The application does not use visx. The source only re-exports @visx/vendor/d3-shape factories, so d3-shape is the clearer direct dependency.

API stability4/5Version 4.0.0 exports 18 established D3 factory names from one source file, leaving little package-specific behavior to change. The current major did replace the packaging contract with root exports and upgrade the vendored d3-shape and d3-path implementations to version 3. Existing named imports remain simple, while any code reaching into @visx/vendor internals or depending on old D3 types needs its own migration review.
Docs3/5The package README explains that curves plug into LinePath and maps all named exports to their D3 counterparts. The root site adds examples and a detailed version 4 migration guide. Selection advice is thin: parameter methods, point requirements, overshoot, and area compatibility live in D3 documentation. The table also says curveBasisClose even though source exports curveBasisClosed, and its Shape example omits the Shape import.
Maintenance4/5npm published 4.0.0 on June 11, 2026, and GitHub records a monorepo push on June 22, 2026. The unarchived airbnb/visx repository has 21,021 stars and 148 open issues and pull requests across many packages. Version 4 modernized entry points, browser targets, React support, and D3 dependencies. The shared repository count cannot be assigned to this small wrapper alone, which has only one re-export source file.
Ecosystem4/5npm counted 5,196,297 downloads from August 18 through August 24, 2026. The exported names and configuration methods match d3-shape, and the factories plug directly into @visx/shape. CommonJS, ESM, bundled declarations, and sideEffects false cover common build setups. Most value comes from the wider visx collection; projects outside it gain less from an extra wrapper around D3's own package.

Use it if

  • Your chart already uses @visx/shape and needs a curve prop that follows the same visx dependency line.
  • A custom chart must switch among linear, step, monotone, basis, cardinal, Catmull-Rom, or natural interpolation.
  • Named imports and the sideEffects false declaration should let the bundler retain only the chosen curve implementation.
  • The team wants D3's familiar curve factories without importing from @visx/vendor internals.
Skip it if

Setup reality

We installed @visx/curve 4.0.0 in a fresh Node 22 Bookworm container. npm finished in 4.4 seconds, left 28 packages, and used 6 MB on disk. npm audit found 0 vulnerabilities at every severity. The package declares 1 direct dependency and 0 peers, is 44 KB unpacked, and includes TypeScript types. Our browser import measured 14.7 KB minified and 2.5 KB gzipped.

Version 4.0.0 is CommonJS with an exports map and a separate ESM entry. Both require() and import worked in our checks. Import from @visx/curve itself; the v4 migration guide makes package roots the supported surface and blocks old deep imports. @visx/vendor 4.0.0 supplies the D3 shape 3 factories. A normal React chart also needs @visx/shape plus whichever scale, axis, group, tooltip, or responsive packages it uses.

Curve choice changes the meaning readers infer from a path. curveMonotoneX assumes ordered x values, while curveMonotoneY assumes ordered y values. curveStepBefore and curveStepAfter assign the horizontal interval to opposite samples. Sort the data before rendering and decide how missing values split the line. Spline families can overshoot or hide sharp changes, so threshold and financial charts need visual checks against the raw points.

Parameterized factories return configured curves: cardinal accepts tension, Catmull-Rom accepts alpha, and bundle accepts beta. curveBundle implements lines rather than area boundaries. Open variants do not connect the outer control points; closed variants join the end back to the start. @visx/curve handles none of the surrounding work, including animation, keyboard interaction, accessible descriptions, clipping, scales, or responsive layout. React-based visx 4 packages require React 18 or 19.

Patterns

Keep straight segments between samples draw-linear-line

import { curveLinear } from '@visx/curve';
import { LinePath } from '@visx/shape';

<LinePath
  data={points}
  x={(point) => xScale(point.x)}
  y={(point) => yScale(point.y)}
  curve={curveLinear}
  stroke="currentColor"
/>

curveLinear connects each sample directly. It is the clearest baseline when smoothing could alter how readers judge the data.

Use monotone interpolation for time smooth-x-series

import { curveMonotoneX } from '@visx/curve';
import { LinePath } from '@visx/shape';

const ordered = [...points].sort((a, b) => a.timestamp - b.timestamp);
<LinePath
  data={ordered}
  x={(point) => xScale(point.timestamp)}
  y={(point) => yScale(point.value)}
  curve={curveMonotoneX}
/>

curveMonotoneX assumes x is ordered. Sort the 1-dimensional sequence before giving it to the path generator.

Use monotone interpolation for ranks smooth-y-series

import { curveMonotoneY } from '@visx/curve';

const ordered = [...points].sort((a, b) => a.rank - b.rank);
<LinePath
  data={ordered}
  x={(point) => xScale(point.value)}
  y={(point) => yScale(point.rank)}
  curve={curveMonotoneY}
/>

curveMonotoneY treats y as the ordered dimension. Ordinary left-to-right time series usually need curveMonotoneX.

Change a step after its timestamp hold-value-until-event

import { curveStepAfter } from '@visx/curve';

<LinePath
  data={events}
  x={(event) => xScale(event.at)}
  y={(event) => yScale(event.value)}
  curve={curveStepAfter}
/>

curveStepAfter holds the current y value until the path reaches the next x coordinate. This fits state that changes at recorded events.

Change a step before its timestamp apply-value-before-event

import { curveStepBefore } from '@visx/curve';

<LinePath
  data={events}
  x={(event) => xScale(event.at)}
  y={(event) => yScale(event.value)}
  curve={curveStepBefore}
/>

curveStepBefore assigns each interval differently from curveStepAfter. Pick the factory that matches when a new value takes effect.

Move each step at the midpoint center-step-change

import { curveStep } from '@visx/curve';

<LinePath
  data={points}
  x={(point) => xScale(point.x)}
  y={(point) => yScale(point.y)}
  curve={curveStep}
/>

curveStep places the vertical change halfway between adjacent x values. That midpoint may imply timing absent from the samples.

Render a natural cubic spline draw-natural-spline

import { curveNatural } from '@visx/curve';

<LinePath
  data={points}
  x={(point) => xScale(point.x)}
  y={(point) => yScale(point.y)}
  curve={curveNatural}
/>

curveNatural can bend beyond sampled values. Overlay points and check peaks before using it for thresholds or money.

Tighten a cardinal curve set-cardinal-tension

import { curveCardinal } from '@visx/curve';

const interpolation = curveCardinal.tension(0.4);
<LinePath
  data={points}
  x={(point) => xScale(point.x)}
  y={(point) => yScale(point.y)}
  curve={interpolation}
/>

curveCardinal.tension accepts values from 0 through 1. Higher tension pulls the result toward straight segments.

Choose Catmull-Rom parameterization set-catmull-rom-alpha

import { curveCatmullRom } from '@visx/curve';

const interpolation = curveCatmullRom.alpha(0.5);
<LinePath
  data={points}
  x={(point) => xScale(point.x)}
  y={(point) => yScale(point.y)}
  curve={interpolation}
/>

An alpha of 0.5 selects centripetal parameterization. Uneven point spacing still needs a visual check for loops and overshoot.

Join the last point to the first close-line-loop

import { curveLinearClosed } from '@visx/curve';

<LinePath
  data={outline}
  x={(point) => xScale(point.x)}
  y={(point) => yScale(point.y)}
  curve={curveLinearClosed}
/>

curveLinearClosed adds the closing segment itself. Duplicating the first point can create an unnecessary zero-length segment.

Treat outer points as spline controls use-open-basis

import { curveBasisOpen } from '@visx/curve';

<LinePath
  data={controlPoints}
  x={(point) => xScale(point.x)}
  y={(point) => yScale(point.y)}
  curve={curveBasisOpen}
/>

curveBasisOpen does not pass through the first and last control points. Small point sets may yield little or no visible path.

Adjust line bundling strength bundle-related-lines

import { curveBundle } from '@visx/curve';

const interpolation = curveBundle.beta(0.85);
<LinePath
  data={routePoints}
  x={(point) => xScale(point.x)}
  y={(point) => yScale(point.y)}
  curve={interpolation}
/>

curveBundle implements line output and lacks the startLine and endLine methods required for area boundaries.

Alternatives

PackageRegistryPick it when
d3-shapenpmUse it directly outside visx or when the same module should also provide line, area, arc, pie, stack, and symbol generators.
@nivo/linenpmUse it when a React line chart should arrive with axes, legends, tooltips, responsiveness, and animation.
rechartsnpmUse it when product code benefits from chart components more than low-level visualization composition.

More web frontend guides

postcss · react · react-dom · tailwindcss · htmlparser2 · tailwind-merge · the whole shelf →

How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.