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

@visx/scale review

@visx/scale 4.0.0 wraps D3 scale constructors in typed configuration objects used across visx charts. Its callable scales map numeric, categorical, temporal, radial, or distribution domains into pixels, colors, sizes, and buckets. The package renders no axis, bar, legend, tooltip, or accessible chart structure. Our full-package browser import measured 50.9 KB minified and 17.7 KB gzipped. Version 4 adds explicit ESM and CommonJS export paths and coordinated package versions across visx; the scale package itself still has no React peer dependency, though related visx 4 React packages require React 18 or 19.

Verdict

@visx/scale 4.0.0 installed in 2.7 seconds and its full import measured 17.7 KB gzipped with 0 audit findings in our sandbox. It fits a visx-based chart system that imports selected factories; use `d3-scale` directly for scale math alone and a higher-level chart library when rendering and accessibility must arrive together.

We installed it

Lab card: what happened when we installed @visx/scaleScreenshot of @visx/scale documentation
Install✓ · 2.7s28 packages on disk · 7 MB
ImportESM import works · require() works · CommonJS package with exports map
Browser17.7 KBgzipped (50.9 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/scale install cleanly?

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

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

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

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

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

Does @visx/scale include TypeScript types?

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

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

d3-scale: Use the upstream constructors directly when visx config helpers add no value. @visx/scale 4.0.0 installed in 2.7 seconds and its full import measured 17.7 KB gzipped with 0 audit findings in our sandbox.

When should you not use @visx/scale?

The project already calls d3-scale directly. This wrapper adds visx config operators without changing the underlying scale model.

API stability4/5The linear, band, point, time, UTC, log, symlog, ordinal, quantile, quantize, and threshold factories retain D3's callable scale behavior. Version 4 changed export paths and requires aligned visx majors, but root imports and core scale configuration remain recognizable. The migration cost sits mostly in package boundaries and coordinated versions rather than new math semantics.
Docs4/5The package page explains domains, ranges, reversed SVG y coordinates, major scale families, log restrictions, and D3 color composition. The main site adds a gallery and a v4 migration guide. Detailed behavior still points readers to D3 documentation, while `createScale`, `updateScale`, `inferScaleType`, generic ticks, mutation, and tree-shaking receive little package-specific explanation.
Maintenance5/5npm published stable 4.0.0 on June 11, 2026, and GitHub records a push on June 22, 2026. The unarchived repository has 21,021 stars and 148 open issues and pull requests. Version 4 shipped coordinated package versions, explicit import and require exports, current ESM output, and React 18 or 19 support guidance for the surrounding visx packages.
Ecosystem5/5npm counted 5,312,314 downloads in the latest completed week. The package connects directly with visx axes, shapes, groups, legends, tooltips, responsive helpers, themes, and XY charts, while its returned functions follow familiar D3 methods. That reach is strong, although a scale-only consumer can avoid the visx-specific wrapper and use `d3-scale` directly.

Use it if

  • A visx chart system wants one object-config style for band, linear, time, log, ordinal, and bucket scales.
  • TypeScript must infer the callable and methods for several D3-style scale families.
  • Runtime configuration chooses a scale `type`, and shared code needs generic tick and update helpers.
  • The application already pays for visx and wants scale behavior aligned with its axes and legends.
Skip it if

Setup reality

We installed @visx/scale 4.0.0 in 2.7 seconds in a fresh Node 22 Bookworm sandbox. It left 28 packages and 7 MB on disk. The package has 1 direct dependency, 0 peer dependencies, 808 KB unpacked, and an MIT license. npm audit found 0 known vulnerabilities. No native build, credential, or configuration file is involved.

The package is CommonJS with an exports map that also points imports to ESM output. Both require() and ESM import worked on our box, and TypeScript declarations are bundled. Import from the package root because visx 4 formalized entry points and removed support for deep internal paths. Related React packages require React 18 or 19, while @visx/scale itself declares no peer.

Our full import bundled to 50.9 KB minified and 17.7 KB gzipped. The package is marked side-effect-free, so production code should import only the scale factories it uses and inspect the actual tree-shaken chunk. Scales are mutable callable objects; updateScale() copies before applying new config. React components should memoize a scale when identity affects children or effects.

Continuous scales extrapolate unless clamped. Band lookups return undefined for unknown categories. Log domains cannot include 0 or cross signs; use symlog for signed data. scaleTime follows local time, while scaleUtc gives consistent time-zone boundaries. Quantize uses equal numeric intervals, quantile uses the sample distribution, and threshold uses explicit breakpoints, so tests should assert the final domain, range, and bucket boundaries.

Patterns

Map a numeric domain to pixels map-linear-values

import { scaleLinear } from '@visx/scale';

const yScale = scaleLinear({
  domain: [0, Math.max(...values)],
  range: [chartHeight, 0],
  nice: true,
  clamp: true,
});

const y = yScale(value);

The `[chartHeight, 0]` range puts larger data values higher in SVG; `nice` can extend the supplied maximum.

Position categorical bars layout-band-chart

import { scaleBand } from '@visx/scale';

const xScale = scaleBand({
  domain: data.map((row) => row.category),
  range: [0, innerWidth],
  padding: 0.2,
  round: true,
});

const x = xScale(row.category);
const width = xScale.bandwidth();

An unlisted category returns `undefined`, so check `x` before using it as an SVG coordinate.

Center categories without bandwidth position-categorical-points

import { scalePoint } from '@visx/scale';

const xScale = scalePoint({
  domain: ['Q1', 'Q2', 'Q3', 'Q4'],
  range: [0, innerWidth],
  padding: 0.5,
});

`scalePoint` has no `bandwidth()` for bar rectangles; it places category centers for dots or vertices.

Create a local-time axis scale scale-local-time

import { scaleTime } from '@visx/scale';

const xScale = scaleTime({
  domain: [new Date(2026, 0, 1), new Date(2026, 11, 31)],
  range: [0, innerWidth],
  nice: true,
});

const ticks = xScale.ticks(6);

Local calendar boundaries can differ around daylight-saving changes; switch to UTC when server and browser ticks must match.

Keep temporal ticks in UTC scale-utc-time

import { scaleUtc } from '@visx/scale';

const xScale = scaleUtc({
  domain: [new Date('2026-01-01T00:00:00Z'), new Date('2026-02-01T00:00:00Z')],
  range: [0, innerWidth],
});

The domain and ticks use UTC boundaries, while label formatting remains a separate explicit choice.

Use a logarithmic scale scale-orders-of-magnitude

import { scaleLog } from '@visx/scale';

const sizeScale = scaleLog({
  domain: [1, 1_000_000],
  range: [2, 40],
  base: 10,
  clamp: true,
});

Both domain ends must stay on one side of 0; a log scale is undefined across zero.

Use symmetric log around zero scale-signed-values

import { scaleSymlog } from '@visx/scale';

const xScale = scaleSymlog({
  domain: [-10_000, 10_000],
  range: [-200, 200],
  constant: 10,
});

The domain can cross 0, and `constant: 10` sets how much of the center behaves linearly.

Map categories to fixed colors assign-category-colors

import { scaleOrdinal } from '@visx/scale';

const colorScale = scaleOrdinal({
  domain: ['success', 'warning', 'error'],
  range: ['#16803c', '#a15c00', '#b42318'],
  unknown: '#777777',
});

The explicit fallback prevents a new category from silently entering the domain and taking a palette slot.

Quantize a numeric interval bin-even-intervals

import { scaleQuantize } from '@visx/scale';

const severity = scaleQuantize({
  domain: [0, 100],
  range: ['low', 'medium', 'high'],
});

console.log(severity(72)); // high

The 0 to 100 interval is split evenly; the number of observations in each bucket may be very different.

Create quantile buckets from samples bin-by-distribution

import { scaleQuantile } from '@visx/scale';

const quartile = scaleQuantile({
  domain: observations,
  range: ['q1', 'q2', 'q3', 'q4'],
});

const boundaries = quartile.quantiles();

Pass the observed sample values because repeated values and outliers determine the returned quantile boundaries.

Map caller-defined breakpoints apply-explicit-thresholds

import { scaleThreshold } from '@visx/scale';

const risk = scaleThreshold({
  domain: [20, 50, 80],
  range: ['minimal', 'low', 'high', 'critical'],
});

Three thresholds require 4 output labels; tests should pin the equality behavior at 20, 50, and 80.

Create a typed scale from configuration create-runtime-scale

import { createScale, getTicks, inferScaleType, updateScale } from '@visx/scale';

const scale = createScale({
  type: 'linear',
  domain: [0, 10],
  range: [0, 400],
});

const resized = updateScale(scale, { range: [0, 800] });
console.log(inferScaleType(resized), getTicks(resized, 5));

`updateScale` leaves the first scale's range unchanged by applying the new config to a copy.

Alternatives

PackageRegistryPick it when
d3-scalenpmUse the upstream constructors directly when visx config helpers add no value.
@nivo/scalesnpmUse it when scales should match Nivo's higher-level chart components.
chroma-jsnpmUse it when color interpolation and color-space conversion are the primary tasks.

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.