mrkeyoor.com_
Sat 08 Aug 22:01 UTC
npmWeb Frontendupdated 08 Aug 2026

@visx/grid

@visx/grid is the SVG gridline package in Airbnb's visx collection of low-level React visualization primitives. GridRows draws horizontal lines from a y scale, GridColumns draws vertical lines from an x scale, and Grid combines both. GridAngle, GridRadial, and GridPolar cover circular charts. You provide scales, pixel dimensions, tick policy, margins, and styling; the components turn scale ticks into React SVG groups, lines, and arcs. It is chart infrastructure, not a complete chart with axes, data marks, tooltips, responsiveness, animation, or accessibility semantics.

Verdict

Excellent grid primitives for teams already choosing visx because they want to own chart composition. If you are not excited to manage scales, sizing, layering, and accessibility yourself, install a higher-level chart library instead.

API stability4/5GridRows, GridColumns, Grid, GridAngle, GridRadial, and GridPolar retain a small prop-driven model built around scales and SVG dimensions, and v4 exports their important prop types from the package root. The v4 migration did introduce real ecosystem constraints: React 18 or 19, synchronized @visx major versions, blocked deep imports, removed runtime PropTypes, modern browser targets, and revised ESM packaging.
Docs4/5The package README gives a concise combined-grid example, while airbnb.io/visx provides a dedicated grid reference and the monorepo links a gallery, changelog, and detailed v4 migration guide. Bundled declarations explain exact versus approximate ticks and every polar prop. The gap is architectural onboarding: developers must combine several package pages to learn responsive sizing, margins, axes, layering, interaction, and accessible SVG practice.
Maintenance5/5Version 4.0.0 was published on 2026-06-11, GitHub reports a push on 2026-06-22, and the unarchived Airbnb monorepo actively documents v4 as the stable line with migration guidance for React, ESM, TypeScript, and browser targets. The repository has 146 open issues and PRs combined, but that count spans the entire multi-package visx project rather than this small grid package alone.
Ecosystem5/5The package recorded 3,667,201 downloads in the measured week and sits inside a 20,999-star visualization ecosystem covering scales, shapes, axes, responsive measurement, tooltips, events, annotations, geo, hierarchy, and more. It accepts visx or compatible D3 scales, supports React 18 and 19, TypeScript, ESM, CommonJS, and Preact through compatibility aliases, while remaining composable with any React animation or styling system.

Use it if

  • You are building a custom SVG chart in React and want grid geometry to stay aligned with the same D3 or visx scales as your axes and marks
  • You need independent row and column styling, exact tick values, custom line rendering, or polar grid primitives
  • You already use other visx v4 packages and prefer composable pieces over a chart configuration framework
  • You need TypeScript-friendly components that support both React 18 and React 19 and publish ESM plus CommonJS entry points
Skip it if

Setup reality

Install `@visx/grid` alongside React 18 or 19. React is a peer dependency, and TypeScript projects should install the matching `@types/react`; that types peer is optional for JavaScript consumers. The package itself depends on six runtime packages: five visx modules plus classnames. Version 4 publishes an exports map with ESM, CommonJS, and declarations, so use package-root imports such as `import { Grid } from '@visx/grid'`; deep imports used by older examples are blocked and unsupported. Upgrade every @visx package in an application to v4 together because the migration guide says their entry points and internal versions changed as a set. The first surprise is how much chart plumbing remains. Grid requires xScale, yScale, width, and height, and those dimensions must already exclude margins if the grid sits inside a translated plot group. It does not observe its container; add @visx/responsive or your own ResizeObserver. `numTicks` is only a hint because D3 chooses pleasant ticks, while `tickValues` provides exact control. Band scales are centered automatically by adding half their bandwidth, and the offset prop adds to that center rather than replacing it. SVG paint order matters, so render grids before marks if they belong behind the data. Lines can intercept pointer events unless you disable pointer events, and decorative grids should be hidden from assistive technology with `aria-hidden`. Grid has no theme context, axis synchronization, clipping, or animation. Polar components use radians, require compatible angle and radial scales, and may need explicit tick arrays to avoid unsuitable domain-derived circles. Server rendering is straightforward because the components are pure React, but responsive measurement happens only in the browser and must avoid a zero-size first layout. Finally, v4 removed generated runtime PropTypes, so JavaScript applications get no runtime prop validation; bad scales or undefined dimensions can quietly produce lines at zero coordinates.

Patterns

Draw rows and columns from two scalesdraw-cartesian-grid

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

const width = 640;
const height = 320;
const xScale = scaleLinear({ domain: [0, 100], range: [0, width] });
const yScale = scaleLinear({ domain: [0, 1], range: [height, 0] });

const grid = (
  <svg width={width} height={height}>
    <Grid
      xScale={xScale}
      yScale={yScale}
      width={width}
      height={height}
      numTicksRows={5}
      numTicksColumns={10}
    />
  </svg>
);

Tick counts are approximate. The scale range and grid dimensions must describe the same plot area.

Render only horizontal grid rowsdraw-horizontal-rows

import { GridRows } from '@visx/grid';

<GridRows
  scale={yScale}
  width={plotWidth}
  numTicks={6}
  stroke='#d7dde5'
  strokeWidth={1}
/>;

GridRows expects a y-position scale. It draws each line from x=0 through the supplied width.

Center columns on a band scaledraw-band-columns

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

const xScale = scaleBand({
  domain: ['Mon', 'Tue', 'Wed'],
  range: [0, plotWidth],
  padding: 0.2,
});

<GridColumns scale={xScale} height={plotHeight} />;

GridColumns adds half of scale.bandwidth() automatically, so each line lands at the center of its band.

Choose exact gridline valuesset-exact-ticks

import { Grid } from '@visx/grid';

<Grid
  xScale={xScale}
  yScale={yScale}
  width={plotWidth}
  height={plotHeight}
  columnTickValues={[0, 25, 50, 75, 100]}
  rowTickValues={[0, 0.5, 1]}
/>;

Explicit tick arrays override the approximate numTicks props and must contain values accepted by their corresponding scales.

Style rows and columns independentlystyle-dashed-grid

import { Grid } from '@visx/grid';

<Grid
  xScale={xScale}
  yScale={yScale}
  width={plotWidth}
  height={plotHeight}
  stroke='#94a3b8'
  strokeDasharray='3 4'
  rowLineStyle={{ opacity: 0.55 }}
  columnLineStyle={{ opacity: 0.25 }}
/>;

The shared stroke props apply to both directions; rowLineStyle and columnLineStyle handle direction-specific CSS properties.

Align the grid with chart marginsposition-with-margins

import { Group } from '@visx/group';
import { Grid } from '@visx/grid';

const margin = { top: 20, right: 24, bottom: 40, left: 48 };
const plotWidth = width - margin.left - margin.right;
const plotHeight = height - margin.top - margin.bottom;

<svg width={width} height={height}>
  <Group left={margin.left} top={margin.top}>
    <Grid xScale={xScale} yScale={yScale} width={plotWidth} height={plotHeight} />
    {dataMarks}
  </Group>
</svg>;

Configure the scales' ranges with plotWidth and plotHeight too. Applying the margin twice shifts grid and marks apart.

Keep decorative lines behind the datalayer-behind-marks

<svg width={width} height={height}>
  <Grid
    xScale={xScale}
    yScale={yScale}
    width={width}
    height={height}
    aria-hidden='true'
    pointerEvents='none'
  />
  <DataSeries data={data} />
</svg>;

SVG uses document order for paint order. Render the grid first, and hide decorative lines from pointer hit-testing and assistive technology.

Render custom horizontal linesrender-custom-lines

import { GridRows } from '@visx/grid';

<GridRows scale={yScale} width={plotWidth} tickValues={[0, 25, 50, 75, 100]}>
  {({ lines }) => (
    <g>
      {lines.map(({ from, to, index }) => (
        <line
          key={index}
          x1={from.x}
          y1={from.y}
          x2={to.x}
          y2={to.y}
          stroke={index === 0 ? '#334155' : '#cbd5e1'}
          strokeWidth={index === 0 ? 2 : 1}
        />
      ))}
    </g>
  )}
</GridRows>;

The render function replaces the default Line elements. Keys use the generated index, so keep tick ordering stable between renders.

Measure a container with ParentSizemake-grid-responsive

import { ParentSize } from '@visx/responsive';
import { Grid } from '@visx/grid';

<ParentSize debounceTime={100}>
  {({ width, height }) => {
    if (width < 1 || height < 1) return null;
    const x = makeXScale(width);
    const y = makeYScale(height);
    return (
      <svg width={width} height={height}>
        <Grid xScale={x} yScale={y} width={width} height={height} />
      </svg>
    );
  }}
</ParentSize>;

Responsiveness is a separate @visx/responsive concern. The first browser measurement can be zero, and server output has no measured size.

Draw spokes for a radial chartdraw-angle-spokes

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

const angleScale = scaleLinear({ domain: [0, 8], range: [0, Math.PI * 2] });

<GridAngle
  scale={angleScale}
  tickValues={[0, 1, 2, 3, 4, 5, 6, 7]}
  innerRadius={24}
  outerRadius={140}
  left={160}
  top={160}
/>;

Angle scale output is in radians. GridAngle rotates its Cartesian conversion so zero begins at the top.

Draw concentric radial grid ringsdraw-radial-rings

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

const radiusScale = scaleLinear({ domain: [0, 100], range: [0, 140] });

<GridRadial
  scale={radiusScale}
  tickValues={[20, 40, 60, 80, 100]}
  left={160}
  top={160}
  stroke='#cbd5e1'
  fill='transparent'
/>;

GridRadial derives the inner radius from the minimum scale domain value. Use explicit ticks when the domain would create an unwanted center ring.

Combine spokes and ringsdraw-polar-grid

import { GridPolar } from '@visx/grid';

<GridPolar
  scaleAngle={angleScale}
  scaleRadial={radiusScale}
  outerRadius={140}
  left={160}
  top={160}
  tickValuesAngle={[0, 1, 2, 3, 4, 5, 6, 7]}
  tickValuesRadial={[20, 40, 60, 80, 100]}
  strokeAngle='#e2e8f0'
  strokeRadial='#cbd5e1'
  strokeDasharrayRadial='2 3'
/>;

GridPolar composes GridAngle and GridRadial. Its angle and radial scales need compatible domains and ranges; the component does not infer chart geometry from data.

Alternatives

PackageRegistryPick it when
rechartsnpmYou want responsive React charts with CartesianGrid, axes, tooltips, legends, and common series assembled at a higher level
victorynpmYou want a batteries-included React chart system with declarative axes, grids, themes, and animation
@nivo/linenpmYou want an opinionated responsive line chart with grids, legends, interactions, SVG or Canvas variants, and polished defaults