mrkeyoor.com_
Wed 23 Sept 02:52 UTC
npmWeb Frontendupdated 22 Sept 2026

@visx/responsive review

@visx/responsive 4.0.0 measures a React container or browser window and passes the dimensions into a chart, or scales a fixed SVG viewBox to fit its wrapper. It supplies useParentSize, ParentSize, useScreenSize, older higher-order components, and ScaleSVG. Version 4 fixes containers stuck at 0 by changing useParentSize to a callback ref, prevents flex and grid height-growth loops with a 2-div ParentSize structure, accepts an external ref, removes lodash, and requires React 18 or 19. It supplies measurements rather than axes, marks, scales, or a finished chart.

Verdict

@visx/responsive 4.0.0 installed 2 packages and 1 MB in 2.1 seconds, while our namespace bundle measured 5 KB gzipped, so it is cheap measurement glue for React 18 or 19 teams already building charts from visx. A generic bounds hook is the better install when no other visx primitive is present.

We installed it

Lab card: what happened when we installed @visx/responsiveScreenshot of @visx/responsive documentation
Install✓ · 2.1s2 packages on disk · 1 MB
ImportESM import works · require() works · CommonJS package with exports map
Browser5 KBgzipped (13.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/responsive install cleanly?

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

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

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

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

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

Does @visx/responsive include TypeScript types?

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

@visx/responsive or react-use-measure: which should you use?

react-use-measure: Use it for general-purpose React bounds measurement with ResizeObserver outside a chart toolkit. @visx/responsive 4.0.0 installed 2 packages and 1 MB in 2.1 seconds, while our namespace bundle measured 5 KB gzipped, so it is cheap measurement glue for React 18 or 19 teams already building charts from visx.

When should you not use @visx/responsive?

The application uses React 16 or 17. visx 4 declares only React 18 and 19; the migration guide directs older apps to visx 3.

API stability3/5ParentSize, useParentSize, ScaleSVG, and the screen-size helpers remain familiar, but v4 changes several integration contracts at once. React 18 or 19 is required, deep imports are closed by an exports map, ParentSize now renders 2 divs, and parentRef became a callback while node exposes the element. Those changes fix real bugs in 0-size and flex/grid layouts. They also require updates to ref access, CSS selectors, DOM snapshots, and older React builds.
Docs4/5The responsive package documentation lists every hook, component, higher-order component, initial-size default, 300 ms debounce, leading-call behavior, ignored dimension, external ref, and ResizeObserver injection option. The v4 migration guide explains the callback ref, 2-div wrapper, peer range, browser target, and exports map. More SSR examples would help: unresolved percentage height, 0 by 0 first render, and structural hydration choices remain easy to miss until a chart disappears.
Maintenance5/5Version 4.0.0 shipped on June 11, 2026, and the repository was pushed on June 22. GitHub reports 21,022 stars, 148 open issues and pull requests, and an unarchived repository. Responsive-specific v4 work fixed callback-ref measurement, flex/grid growth loops, and external ref support, while the monorepo removed lodash and added React 19. The release includes a detailed migration guide and follows a public alpha series, evidence of active testing rather than a dormant package bump.
Ecosystem5/5npm counted 4,737,762 downloads in the latest completed week. @visx/responsive fits directly beside visx shape, scale, axis, tooltip, and XYChart packages, and publishes CommonJS, ESM, an exports map, and TypeScript declarations for React 18 and 19. Generic ResizeObserver hooks can replace it, but they do not share visx's component naming or examples. Its strongest value comes when a team already composes visualization primitives from the same monorepo.

Use it if

  • A chart built from visx primitives needs width and height from its actual dashboard container.
  • ResizeObserver measurement needs initial dimensions, debounce control, ignored fields, a polyfill hook, or a caller-owned ref.
  • Legacy React components still need withParentSize or withScreenSize while newer code uses hooks.
  • A fixed-coordinate SVG can scale as one unit without recomputing tick count or label layout.
Skip it if

Setup reality

We installed @visx/responsive 4.0.0 in a fresh Node 22 Bookworm sandbox. npm completed in 2.1 seconds and left 2 packages using 1 MB. The package is 216 KB unpacked, declares 0 direct dependencies and 2 peer dependencies, and produced 0 npm audit findings. It is CommonJS with an exports map and bundled TypeScript declarations; both require() and ESM import worked. Our namespace browser build measured 13.9 KB minified and 5 KB gzipped.

Install React 18 or 19, plus matching @types/react for TypeScript. No provider, stylesheet, credentials, or config file is required. Layout is the setup: ParentSize defaults to 100% width and height, so its ancestor needs a resolved height. Version 4 renders an outer wrapper and an absolute measurement div to stop flex and grid feedback loops. CSS selectors and snapshots built around the v3 single-wrapper DOM need updating.

useParentSize returns a callback parentRef in v4, not an object with .current. Read node for the measured element or pass externalRef when another feature needs the same DOM node. Dimensions begin at 0 by 0 unless initialSize is supplied, then update after mount through ResizeObserver and requestAnimationFrame. Server-rendered charts should use a stable estimate or render a placeholder with the same outer structure to avoid a sharp layout jump.

Resize updates are debounced by 300 ms by default and can fire on the leading edge. Lowering debounceTime makes drag-resizing feel quicker but adds React renders. Test environments and old browsers need resizeObserverPolyfill. ScaleSVG takes a design width and height and scales strokes, labels, and marks together; it never chooses new ticks for the rendered pixel width. The v4 exports map blocks undocumented deep imports, so use only names exported from @visx/responsive.

Patterns

Give a chart its container dimensions measure-parent-component

<div style={{ width: '100%', height: 360 }}>
  <ParentSize>
    {({ width, height }) =>
      width > 0 && height > 0 ? <Chart width={width} height={height} /> : null
    }
  </ParentSize>
</div>

The ancestor has an explicit 360 px height. ParentSize cannot derive 100% height from an auto-sized containing block.

Attach measurement to your own container measure-parent-hook

function ResponsiveChart() {
  const { parentRef, width, height } = useParentSize();
  return (
    <div ref={parentRef} style={{ width: '100%', height: 320 }}>
      {width > 0 && height > 0 && <Chart width={width} height={height} />}
    </div>
  );
}

In v4 parentRef is a callback. Use the returned node value instead of parentRef.current.

Start from a useful server-render size set-ssr-initial-size

const { parentRef, width, height } = useParentSize({
  initialSize: { width: 640, height: 360 },
});

The 640 by 360 estimate is replaced after mount. Pick a stable placeholder size to limit layout movement.

Update sooner during container drags reduce-resize-delay

const size = useParentSize({
  debounceTime: 50,
  enableDebounceLeadingCall: true,
});

The default is 300 ms. A 50 ms delay feels more immediate but can schedule more React renders during continuous resize.

Provide ResizeObserver for an older runtime inject-resize-observer

import { ResizeObserver } from '@juggle/resize-observer';

const size = useParentSize({
  resizeObserverPolyfill: ResizeObserver,
});

The polyfill is not one of the package's 0 direct dependencies. Install and pass it yourself.

Forward the container to another feature share-measured-element-ref

const containerRef = useRef<HTMLDivElement>(null);
const { parentRef, node, width } = useParentSize<HTMLDivElement>({
  externalRef: containerRef,
});

return <div ref={parentRef}>{width > 0 && <Chart width={width} />}</div>;

externalRef and node point at the same element measured by the callback ref in v4.

Render only for size changes ignore-position-only-changes

const size = useParentSize({
  ignoreDimensions: ['top', 'left'],
});

A top or left change alone does not replace state. Width and height changes still carry the full new measurement.

Size a full-window visualization measure-browser-window

const { width, height } = useScreenSize({
  initialSize: { width: 1280, height: 720 },
  debounceTime: 100,
});
return <Chart width={width} height={height} />;

useScreenSize reads window dimensions after mount. Nested dashboard charts should measure their parent instead.

Fit one fixed SVG coordinate system scale-fixed-viewbox

<ScaleSVG width={800} height={400}>
  <ChartMarks width={800} height={400} />
</ScaleSVG>

ScaleSVG scales all marks, text, and strokes from an 800 by 400 viewBox. It does not recompute label density.

Fill the wrapper and crop excess crop-scaled-svg

<ScaleSVG
  width={800}
  height={400}
  preserveAspectRatio="xMidYMid slice"
>
  <ChartMarks width={800} height={400} />
</ScaleSVG>

slice fills the viewport and may crop chart edges. The default meet behavior keeps the whole viewBox visible.

Measure a legacy component through an HOC wrap-class-chart

function Chart({ parentWidth, parentHeight }) {
  if (parentWidth == null || parentHeight == null) return null;
  return <svg width={parentWidth} height={parentHeight} />;
}

export default withParentSize(Chart);

withParentSize supports older component patterns. New function components can use useParentSize directly.

Set a manual ParentSize value override-parent-size

<ParentSize initialSize={{ width: 400, height: 240 }}>
  {({ width, height, resize }) => (
    <>
      <Chart width={width} height={height} />
      <button onClick={() => resize({ width: 800, height, top: 0, left: 0 })}>Wide</button>
    </>
  )}
</ParentSize>

resize() passes through debounce and sets all 4 fields. The next ResizeObserver event can replace the manual width.

Alternatives

PackageRegistryPick it when
react-use-measurenpmUse it for general-purpose React bounds measurement with ResizeObserver outside a chart toolkit.
use-resize-observernpmUse it for a focused hook with rounding, callbacks, and observed-box controls.
@react-hook/resize-observernpmUse it when an existing ref should receive lightweight ResizeObserver updates.
react-resize-detectornpmUse it when a general React hook or component wrapper is preferable to visx-specific naming.

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.