mrkeyoor.com_
Sat 08 Aug 21:02 UTC
npmWeb Frontendupdated 08 Aug 2026

@visx/curve

@visx/curve is a small set of named exports for choosing how SVG lines interpolate between data points. It re-exports D3's linear, step, basis, bundle, cardinal, Catmull-Rom, monotone, and natural curve factories through @visx/vendor. You normally pass one of them to the curve prop on @visx/shape components such as LinePath. It does not draw a chart, scale data, render axes, handle tooltips, or animate anything by itself, and despite the visx name its own API contains no React components.

Verdict

Worth installing beside @visx/shape when you want visx-aligned D3 curve imports. Outside a visx chart stack, install d3-shape directly or choose a complete charting library if interpolation is only one small part of the job.

API stability4/5The public surface is a short list of established D3 curve factory names, and the package source is only re-exports, which leaves little custom behavior to break. Version 4 did upgrade the underlying d3-shape and d3-path packages to v3 through @visx/vendor, and the migration guide tells direct vendor importers to review D3 v3 API and type changes, so a major upgrade still deserves a visual regression pass.
Docs3/5The package README explains its purpose, shows direct and namespace imports, and lists the available D3 equivalents. The root visx site adds a gallery and migration guide. Depth is limited, though: curve selection tradeoffs and parameter methods are left to D3 documentation, the package example uses a Shape namespace without showing its import, and the function table contains a curveBasisClose naming typo while the actual export is curveBasisClosed.
Maintenance4/5Version 4.0.0 was published on June 11, 2026, and the monorepo was pushed on June 22, 2026. The v4 migration work updated D3 dependencies, modernized ESM output for strict runtimes, and documented browser targets. GitHub reports 146 open issues and pull requests across the entire multi-package visx repository, so that count should not be read as the burden of this tiny wrapper alone.
Ecosystem4/5npm recorded 4,271,595 downloads for the measured week, and the airbnb/visx monorepo has 20,999 stars. The factories plug directly into @visx/shape and retain D3's familiar names and parameter methods, making examples transferable. The package is most valuable inside the larger visx collection; by itself it has little ecosystem beyond the D3 implementation it re-exports.

Use it if

  • You already use @visx/shape and want a supported named import for line or area interpolation
  • You need to switch among linear, stepped, monotone, basis, cardinal, Catmull-Rom, or natural curves without importing D3 directly
  • You are building a custom chart system from low-level visx pieces and want curve factories aligned with visx's vendored D3 version
  • You want named ESM exports from a package marked side-effect-free so a modern bundler can retain only the curve code your chart uses
Skip it if

Setup reality

Installing npm install @visx/curve gives you the curve factories and bundled TypeScript declarations with no peer dependency. The package does bring @visx/vendor 4.0.0, which in visx 4 wraps d3-shape 3 and d3-path 3. In a normal React chart you will separately install @visx/shape and whichever scale, axis, group, tooltip, or responsive packages you actually use. The root visx README says its v4 React components require React 18 or 19, even though @visx/curve itself has no React peer and its exports are plain functions. Choose the curve based on data meaning, not visual softness: curveMonotoneX assumes x is the independent ordered dimension, curveMonotoneY is for the opposite orientation, and stepBefore versus stepAfter changes which sample owns the interval. Closed and open variants change endpoint behavior and need enough points to look sensible. Parameterized factories use calls such as curveCardinal.tension(0.4), curveCatmullRom.alpha(0.5), and curveBundle.beta(0.85). The bundle curve is for lines, not areas. Curves only change path interpolation; sorting data, handling missing values, clipping overshoot, scales, rendering, animation, and accessible descriptions remain your responsibility. Prefer named imports so bundlers can use the package's sideEffects: false metadata.

Patterns

Connect points with straight segmentsdraw-linear-line

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

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

Linear interpolation is the safest default when each sample should remain visibly exact.

Smooth an x-ordered series without vertical overshootsmooth-time-series

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

<LinePath
  data={[...points].sort((a, b) => a.time - b.time)}
  x={(d) => xScale(d.time)}
  y={(d) => yScale(d.value)}
  curve={curveMonotoneX}
/>

Sort by x first; curveMonotoneX assumes x is monotonic and preserves monotonicity in y between neighboring samples.

Use monotone interpolation along the y axissmooth-vertical-series

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

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

Use this only when y is the ordered independent dimension; ordinary time series normally need curveMonotoneX.

Draw a natural cubic splinedraw-natural-spline

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

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

Natural splines are visually soft but can bend beyond sampled values, so they are a poor fit for strict threshold or financial charts.

Hold each value until the next sampledraw-step-after

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

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

curveStepAfter changes y after reaching the next x coordinate, which fits values that remain active until the next event.

Apply the next value before its sample pointdraw-step-before

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

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

The ownership of each horizontal interval is opposite curveStepAfter; check the domain meaning before choosing one.

Switch values halfway between samplesdraw-midpoint-steps

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

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

curveStep moves the vertical transition to the midpoint, which looks balanced but may imply a transition time not present in the data.

Tune cardinal spline tensionadjust-cardinal-tension

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

const curve = curveCardinal.tension(0.35);

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

Tension must be between 0 and 1; increasing it pulls the curve toward straighter segments.

Configure Catmull-Rom parameterizationadjust-catmull-rom-alpha

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

const centripetal = curveCatmullRom.alpha(0.5);

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

Alpha 0.5 selects centripetal parameterization; unevenly spaced points still deserve visual tests for loops or overshoot.

Close a polyline back to its first pointdraw-closed-loop

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

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

The closed factory adds the closing segment, so do not duplicate the first point at the end unless your data model requires it.

Use an open basis splinedraw-open-basis-curve

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

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

Open spline variants do not pass through or connect the outer control points and need enough points to produce a useful segment.

Tune a bundled linetune-bundle-curve

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

const bundled = curveBundle.beta(0.85);

<LinePath
  data={routePoints}
  x={(d) => xScale(d.x)}
  y={(d) => yScale(d.y)}
  curve={bundled}
/>

curveBundle is intended for lines and does not implement the area boundary methods needed by area generators.

Alternatives

PackageRegistryPick it when
d3-shapenpmUse it directly when you are outside visx or also need line, area, arc, pie, stack, and symbol generators.
@nivo/linenpmUse it when you want an opinionated React line chart with axes, legends, tooltips, responsiveness, and animation included.
rechartsnpmUse it when a component-level React chart API is more valuable than composing low-level visualization primitives.