はじめに
Rechartsで作ったグラフに「あと少しだけ」デザイン調整を加えようとして、propsの海に溺れた経験はありませんか。あるいはd3.jsで完全に自由なチャートを作ろうとして、useEffectの中でDOMを直接操作するコードがReactの流儀と衝突し、頭を抱えたことはないでしょうか。
「高機能なチャートライブラリは自由が利かない。d3は自由だがReactと相性が悪い」——このジレンマに対するAirbnbの回答が、今回紹介するvisxです。d3の計算能力だけを借りて、描画はReactに任せる。この割り切った設計が、既製チャートの限界を感じ始めた開発者に刺さります。
visxとは
visx(ヴィスエックス)は、Airbnbが開発・公開しているReact向けの低レベル可視化コンポーネント集です。名前は「visualization components」に由来し、GitHubで21,000を超えるスターを獲得しています。2026年6月にはメジャーバージョンとなるv4がリリースされ、React 18/19に対応した現役バリバリのライブラリです。
最大の特徴は、「チャートライブラリ」ではなく「チャートライブラリを作るための部品集」である点です。スケール計算やパス生成などの数学的な処理は内部でd3を使いつつ、DOMの管理は完全にReactに委ねます。d3のセレクションやデータバインディングを覚える必要はありません。
主な特徴
- 低レベル&非依存な設計 - 完成品のチャートではなく、軸・スケール・図形などの部品を提供します。デザインもアニメーションも自分たちで完全にコントロールできます
- パッケージ分割によるバンドル最適化 -
@visx/scale、@visx/shapeなど30以上の小さなパッケージに分かれており、必要なものだけをインストールできます - d3の知識が(ほぼ)不要 - d3は計算エンジンとして裏方に徹するため、開発者は普段どおりJSXでSVG要素を組み立てるだけです
- 社内チャートライブラリの基盤に最適 - 「意見を持たない」設計のため、チーム独自のデザインシステムに沿った可視化コンポーネントを構築する土台になります
インストール
visxはモノレポ構成で、必要なパッケージだけを個別にインストールします。まずは棒グラフに必要な最小構成から始めましょう。
# npm
npm install @visx/group @visx/shape @visx/scale @visx/mock-data
# yarn
yarn add @visx/group @visx/shape @visx/scale @visx/mock-data
# pnpm
pnpm add @visx/group @visx/shape @visx/scale @visx/mock-data
全部入りの@visx/visxパッケージも存在しますが、バンドルサイズが膨らむため、本番では個別インストールが推奨されています。なお、v4はReact 18以上が必要です。
基本的な使い方
まずは最もシンプルな棒グラフを作ってみます。visxの流儀は「スケールで座標を計算し、JSXでSVGを組み立てる」の2段構えです。
import { Bar } from '@visx/shape';
import { Group } from '@visx/group';
import { scaleBand, scaleLinear } from '@visx/scale';
import { letterFrequency } from '@visx/mock-data';
const data = letterFrequency.slice(0, 10);
const width = 500;
const height = 300;
const margin = { top: 20, right: 20, bottom: 20, left: 20 };
const xMax = width - margin.left - margin.right;
const yMax = height - margin.top - margin.bottom;
// x軸: 文字ごとの帯域を等分するスケール
const xScale = scaleBand<string>({
range: [0, xMax],
domain: data.map((d) => d.letter),
padding: 0.4,
});
// y軸: 出現頻度を高さに変換する線形スケール
const yScale = scaleLinear<number>({
range: [yMax, 0],
domain: [0, Math.max(...data.map((d) => d.frequency))],
});
export function LetterBarChart() {
return (
<svg width={width} height={height}>
<Group left={margin.left} top={margin.top}>
{data.map((d) => {
const barWidth = xScale.bandwidth();
const barHeight = yMax - (yScale(d.frequency) ?? 0);
return (
<Bar
key={d.letter}
x={xScale(d.letter)}
y={yMax - barHeight}
width={barWidth}
height={barHeight}
fill="#6366f1"
/>
);
})}
</Group>
</svg>
);
}
注目してほしいのは、data.map()でJSXを返しているだけという点です。d3のselectAll().data().enter()のような独特の作法は一切登場しません。scaleBandやscaleLinearが「データ値 → ピクセル座標」の変換を担い、描画はいつものReactです。状態管理もメモ化も、普段のReactの知識がそのまま通用します。
実践的なユースケース
軸とグリッド付きの折れ線チャート
実務でよく必要になる、軸・グリッド線付きの時系列チャートを作ってみます。@visx/axisと@visx/gridを追加でインストールしてください。
npm install @visx/axis @visx/grid @visx/curve
import { LinePath } from '@visx/shape';
import { Group } from '@visx/group';
import { scaleTime, scaleLinear } from '@visx/scale';
import { AxisBottom, AxisLeft } from '@visx/axis';
import { GridRows } from '@visx/grid';
import { curveMonotoneX } from '@visx/curve';
type DataPoint = { date: Date; value: number };
const data: DataPoint[] = [
{ date: new Date('2026-01-01'), value: 120 },
{ date: new Date('2026-02-01'), value: 180 },
{ date: new Date('2026-03-01'), value: 150 },
{ date: new Date('2026-04-01'), value: 240 },
{ date: new Date('2026-05-01'), value: 210 },
{ date: new Date('2026-06-01'), value: 300 },
];
const width = 600;
const height = 320;
const margin = { top: 20, right: 20, bottom: 40, left: 50 };
const xMax = width - margin.left - margin.right;
const yMax = height - margin.top - margin.bottom;
const xScale = scaleTime({
range: [0, xMax],
domain: [data[0].date, data[data.length - 1].date],
});
const yScale = scaleLinear({
range: [yMax, 0],
domain: [0, 320],
nice: true, // 目盛りをキリのよい値に丸める
});
export function MonthlyTrendChart() {
return (
<svg width={width} height={height}>
<Group left={margin.left} top={margin.top}>
<GridRows scale={yScale} width={xMax} stroke="#e5e7eb" />
<LinePath<DataPoint>
data={data}
x={(d) => xScale(d.date)}
y={(d) => yScale(d.value)}
stroke="#10b981"
strokeWidth={2.5}
curve={curveMonotoneX}
/>
<AxisLeft scale={yScale} numTicks={5} />
<AxisBottom top={yMax} scale={xScale} numTicks={6} />
</Group>
</svg>
);
}
curveMonotoneXを渡すだけで滑らかな曲線になり、nice: trueでy軸の目盛りが整います。d3の便利な機能を、Reactコンポーネントのpropsとして自然に使えるのがvisxの気持ちよさです。
ツールチップでインタラクティブに
可視化に欠かせないツールチップも、@visx/tooltipのフックで宣言的に書けます。
npm install @visx/tooltip @visx/event
import { useTooltip, TooltipWithBounds } from '@visx/tooltip';
import { localPoint } from '@visx/event';
export function InteractiveBar({ d, x, y, barWidth, barHeight }: {
d: { letter: string; frequency: number };
x: number; y: number; barWidth: number; barHeight: number;
}) {
const { showTooltip, hideTooltip, tooltipData, tooltipLeft, tooltipTop } =
useTooltip<string>();
return (
<>
<rect
x={x}
y={y}
width={barWidth}
height={barHeight}
fill="#6366f1"
onMouseMove={(event) => {
const point = localPoint(event);
showTooltip({
tooltipData: `${d.letter}: ${(d.frequency * 100).toFixed(1)}%`,
tooltipLeft: point?.x,
tooltipTop: point?.y,
});
}}
onMouseLeave={hideTooltip}
/>
{tooltipData && (
<TooltipWithBounds left={tooltipLeft} top={tooltipTop}>
{tooltipData}
</TooltipWithBounds>
)}
</>
);
}
TooltipWithBoundsは画面端でのはみ出しを自動で防いでくれます。ホバー対象は素のSVG要素なので、Tailwind CSSでのスタイリングやFramer Motionでのアニメーションとも自由に組み合わせられます。
こんな場面でvisxが効きます
- デザインシステムに完全準拠したダッシュボード - 既製ライブラリの「それっぽい見た目」ではなく、自社ブランドどおりのチャートを部品から組み上げられます
- 社内共通チャートライブラリの構築 - visxを土台に「自社用Recharts」を作るイメージです。Airbnb自身がこの目的で開発しました
- 既製ライブラリにない特殊な可視化 - サンキー図やヒートマップ、地理データ(
@visx/geo)など、テンプレートの外にある表現も部品の組み合わせで実現できます
逆に、「とにかく5分でグラフを出したい」だけならRechartsやChart.jsの方が早いのも事実です。visxは自由度と引き換えに、レイアウトを自分で組む手間を受け入れるライブラリだと理解しておきましょう。
まとめ
visxは、d3の計算力とReactの宣言的UIを橋渡しする低レベル可視化コンポーネント集です。本記事のポイントを振り返ります。
- visxは完成品のチャートではなく、チャートを作るための部品集である
- スケールで座標を計算し、JSXでSVGを組み立てるだけ。d3特有の作法は不要
- パッケージが細かく分割されており、必要な分だけ入れればバンドルも軽量
- デザインの完全なコントロールが必要なダッシュボードや、社内チャートライブラリの基盤に最適
まずは本記事の棒グラフをコピペして動かし、色や形を自分好みに変えるところから始めてみてください。「チャートライブラリのpropsと格闘する日々」から、「チャートを設計する楽しさ」へ。visxがその入り口になるはずです。