File: README.md
visx
visx is a collection of reusable low-level visualization components. visx combines the power of d3
to generate your visualization with the benefits of react for updating the DOM.
[!IMPORTANT]
visx v4 is the current stable release and requires React 18 or 19.bashnpm install @visx/shapeUpgrading from v3? See the visx 4 migration guide.
Usage
Let's make a simple bar graph.
First we'll install the relevant packages:
npm install --save @visx/mock-data @visx/group @visx/shape @visx/scaleimport React from 'react';
import { letterFrequency } from '@visx/mock-data';
import { Group } from '@visx/group';
import { Bar } from '@visx/shape';
import { scaleLinear, scaleBand } from '@visx/scale';
// We'll use some mock data from `@visx/mock-data` for this.
const data = letterFrequency;
// Define the graph dimensions and margins
const width = 500;
const height = 500;
const margin = { top: 20, bottom: 20, left: 20, right: 20 };
// Then we'll create some bounds
const xMax = width - margin.left - margin.right;
const yMax = height - margin.top - margin.bottom;
// Accessors
const getLetter = (d) => d.letter;
const getFrequency = (d) => d.frequency * 100;
// And then scale the graph by our data
const xScale = scaleBand({
range: [0, xMax],
round: true,
domain: data.map(getLetter),
padding: 0.4,
});
const yScale = scaleLinear({
range: [yMax, 0],
round: true,
domain: [0, Math.max(...data.map(getFrequency))],
});
// Finally we'll embed it all in an SVG
function BarGraph() {
return (
<svg width={width} height={height}>
{data.map((d) => {
const letter = getLetter(d);
const barHeight = yMax - (yScale(getFrequency(d)) ?? 0);
return (
<Group key={`bar-${letter}`}>
<Bar
x={xScale(letter)}
y={yMax - barHeight}
height={barHeight}
width={xScale.bandwidth()}
fill="#fc2e1c"
/>
</Group>
);
})}
</svg>
);
}For more examples using visx, check out the gallery.
Motivation
Goal
The goal is to create a library of components you can use to make both your own reusable chart
library or your slick custom one-off chart. visx is largely unopinionated and is meant to be built
upon. Keep your bundle sizes down and use only the packages you need.
How?
Under the hood, visx is using d3 for the calculations and math. If you're creating your own awesome
chart library on top of visx, it's easy to create a component api that hides d3 entirely. Meaning
your team could create charts as easily as using reusable react components.
But why?
Mixing two mental models for updating the DOM is never a good time. Copy and pasting d3 code intouseEffect() is just that. This collection of components lets you easily build your own reusable
visualization charts or library without having to learn d3. No more selections orenter()/exit()/update().
FAQ
What does
visxstand for?visx stands for visualization components.
Do you plan on supporting animation/transitions?
A common criticism of visx is it doesn't have animation baked in, but this was a conscious
choice. It's a powerful feature to not bake it in.Imagine your app already bundles
react-motion, adding a hypothetical@visx/animationis
bloat. Since visx is react, it already supports all react animation libs.Charting libraries are like style guides. Each org or app will eventually want full control
over their own implementation.visx makes this easier for everyone. No need to reinvent the wheel each time.
more info: https://github.com/airbnb/visx/issues/6
Do I have to use every package to make a chart?
nope! pick and choose the packages you need.
Can I use this to create my own library of charts for my team?
Please do.
Does visx work with preact?
yup! alias
react+react-domtopreact/compat. For visx v4, configure your package
manager to satisfy the React 18/19 peer dependency range.I like using d3.
Me too.
Thanks
Thanks to Happo for providing the visual regression testing platform that
helps us review UI changes and catch unintended visual regressions.
Development
Please see CONTRIBUTING.md
:v:
File: ATTRIBUTION.md
File: CODE_OF_CONDUCT.md
Contributor Covenant Code of Conduct
Airbnb has adopted a Code of Conduct that we expect project participants to adhere to. Please
read the full Code of Conduct text so that you can understand
what actions will and will not be tolerated. Report violations to the maintainers of this project or
to [email protected].
Reports sent to [email protected] are received
by Airbnb's open source code of conductmoderation team, which is composed of Airbnb employees. All
communications are private and confidential.
File: CONTRIBUTING.md
Contributing
Contributions welcome! Please follow the code of conduct.
Overview
Yarn workspaces are used to manage dependencies and
build config across packages in the umbrella visx monorepo, and
lerna is used to manage versioning.
Project structure
visx/
lerna.json
package.json
packages/
visx-package-1/
src/
test/
build/
package.json
...
visx-package-2/
...
...Local development
Run the following to setup your local dev environment:
# Install `yarn`, alternatives at https://yarnpkg.com/en/docs/install
curl -o- -L https://yarnpkg.com/install.sh | bash
# Clone or fork `visx`
git clone [email protected]:airbnb/visx.git # or your fork
cd visx
# install dependencies, and have `yarn` symlink within-`visx` dependencies
yarn
# build packages and generate types for local development
yarn buildRebuild specific package(s)
Upon modification of a single package you can run the following to rebuild it. Note that you can
specify multiple packages to build this way, and optionally append --watch to continuously watch
for changes.
# build the specified package(s) as cjs + esm versions
# example `PKG=@visx/axis yarn babel:pkg`
PKG=@visx/{package[,package]} yarn babel:pkg
# generate d.ts(definition files) the specified package(s)
# and rebuild any other packages the specified package(s) depend on
# example `PKG=@visx/axis yarn type:pkg`
PKG=@visx/{package[,package]} yarn type:pkgfrom the visx monorepo root to re-build the package with your changes.
Running demo pages
You can use the local next.js dev server within packages/visx-demo to view
and iterate on your changes in the gallery. From the packages/visx-demo folder run yarn dev to
start the next server which (if correctly sym-linked) will also watch for changes you make to other
packages (upon re-building them, see above section).
Config generation
visx uses @airbnb/nimbus to generate build configuration foreslint, prettier, jest, babel, and typescript.
File: lerna.json
{
"packages": [
"packages/*"
],
"version": "4.0.0",
"command": {
"publish": {
"allowBranch": "master"
}
},
"$schema": "node_modules/lerna/schemas/lerna-schema.json"
}
File: MIGRATION.md
Upgrading to visx 4
visx 4 is the current major release. It modernizes React support, package entry points, browser
targets, and the published ESM output. For most apps, the upgrade is:
- Upgrade all
@visx/*packages together to^4.0.0. - Use React 18 or 19.
- Replace deep imports like
@visx/shape/lib/shapes/Barwith package-root imports like@visx/shape. - If you use TypeScript, install
@types/reactand, when needed,@types/react-domusing the
major version that matches your React version. - If you use
withBoundingRects, attach its injectednodeRefto the DOM element you want
measured. - If you rely on generated runtime
propTypes, migrate those checks into your app. - If you still need IE11, stay on visx 3.
4.1 (coming soon)
`@visx/kernel` adds shared primitives for first-party hooks
visx 4.1 introduces @visx/kernel, a small shared package for the cross-cutting primitives used by
first-party hooks: structural memoization, accessor normalization, stable callbacks, stable refs,
stable ids, domain computation, number formatting, path-string helpers, Path2D caching, and
structured development warnings.
The package gives first-party hooks a consistent place to normalize user input before doing
package-specific math when that normalization is appropriate. Existing component APIs do not change,
and @visx/kernel does not add rendering opinions.
What you need to do: nothing unless you want to build directly on these low-level primitives.
Existing visx charts continue to work. Future hook APIs may use @visx/kernel internally, but
consumers do not need to install or import it directly unless they opt in.
`@visx/theme` adds shared visual tokens for primitive charts
visx 4.1 introduces @visx/theme, an optional package for sharing chart colors, typography, axis,
grid, and layout defaults across low-level visx charts. The package keeps visx primitives
prop-driven: @visx/axis, @visx/grid, and @visx/shape do not read theme context automatically.
Use the server-compatible root entry when a chart only needs scoped CSS variables:
import { ThemeScope } from '@visx/theme';
<ThemeScope theme="auto">
<Chart />
</ThemeScope>;Use the client entry when chart components need hook-derived props:
import { ThemeProvider, useAxisStyle, useGridStyle, useColor } from '@visx/theme/react';theme="auto" is designed for shadcn/ui-style CSS variables such as --chart-1, --background,--border, and --muted-foreground. It does not install a mode switcher, read the DOM, or update
JS-only layout values when a CSS class changes.
Existing @visx/xychart themes remain supported for XYChart. New primitive charts can reuse the
same visual choices with fromXYChartTheme from @visx/theme.
What you need to do: nothing unless you want to opt in. Existing visx charts continue to work.
Add @visx/theme only when you want shared visual tokens or shadcn/ui-compatible CSS variable
theming for primitive charts.
`@visx/a11y` adds opt-in accessibility helpers for primitive charts
visx 4.1 introduces @visx/a11y, an optional package for adding chart semantics to primitive SVG
charts. It provides server-safe helpers for generated ARIA props, text descriptions, and hidden data
tables, plus a @visx/a11y/react entry for pre-bound chart props, roving keyboard focus, data-table
fallback, and live announcements.
These helpers do not replace the chart render tree or hide non-data elements automatically. If your
chart includes decorative chrome such as grid lines, axis ticks, background rectangles, or clipping
helpers, render those elements with aria-hidden="true" so assistive technology focuses on the
chart title, description, series, data marks, and table fallback.
What you need to do: nothing unless you want to opt in. Existing visx charts continue to work.
Add @visx/a11y only when you want generated chart semantics, keyboard exploration, or a data-table
fallback for primitive charts.
Registry-oriented hooks for primitive charts
visx 4.1 adds the first hook and helper APIs used to build primitive charts for the visx chart
registry. These APIs are additive and live in package roots or explicit React subpaths:
import {
getPositiveDomain,
getResponsiveWidth,
getZeroBaselineDomain,
useChartDimensions,
} from '@visx/chart';
import { useAxis } from '@visx/axis/react';
import { useScale } from '@visx/scale/react';
import { arcPath, areaPath, linePath } from '@visx/shape';
import { usePie } from '@visx/shape/react';
import { useColorScale } from '@visx/theme/react';
import { useVoronoi } from '@visx/voronoi/react';Existing component APIs continue to work. <Axis /> and `` reuse the extracted hook logic
internally, but their public props and rendering behavior are unchanged. Hooks that need React are
exported from /react subpaths; root package imports such as @visx/scale remain available for
non-React code.
What you need to do: nothing unless you want to author hook-based primitive charts. Continue
using existing components as before, or opt into the new hooks from the import paths above.
`@visx/tooltip/floating` adds modern tooltip primitives
visx 4.1 adds an optional Floating UI-backed tooltip surface under the @visx/tooltip/floating
subpath. It includes low-level FloatingTooltip primitives, useFloatingTooltip, config-driven
chart tooltip content, and the useChartTooltip plus ChartTooltip convenience layer for
data-driven chart tooltips.
import {
ChartTooltip,
FloatingTooltip,
useChartTooltip,
useFloatingTooltip,
} from '@visx/tooltip/floating';The new APIs are additive. Existing @visx/tooltip root exports, useTooltip,useTooltipInPortal, Tooltip, TooltipWithBounds, and withTooltip remain unchanged.
What you need to do: nothing unless you want Floating UI positioning, virtual anchors,
trigger-based interactions, or config-driven chart tooltip content. Continue using the existing
tooltip APIs as before, or opt into the new @visx/tooltip/floating subpath for new tooltip work.
The visx chart registry adds shadcn-compatible chart starters
visx 4.1 introduces a source-first chart registry for installing themed, responsive, accessible
primitive chart components into application code with the shadcn CLI.
npx shadcn@latest add airbnb/visx/line-chartRegistry items are copied into your app as editable source files and depend on public visx packages
such as @visx/a11y, @visx/chart, @visx/responsive, and @visx/theme. The registry itself is
distribution infrastructure and is not a runtime package your app imports.
What you need to do: nothing unless you want drop-in primitive chart starters. Existing visx
charts continue to work. Use registry installs only after the referenced 4.1 visx packages are
published.
From visx 3.x
Upgrade every visx package in your application at the same time. Mixing visx 3 and visx 4 packages
is not recommended because package entry points, peer dependency ranges, and internal package
dependencies changed together.
npm install @visx/shape@^4 @visx/scale@^4With Yarn, upgrade the visx packages your app depends on to the same major:
yarn up "@visx/*@^4.0.0"React 18 or 19 is required
React-based @visx/* packages declare react peer dependencies as ^18.0.0 || ^19.0.0. Packages
that depend on react-dom declare the same supported range for their react-dom peer dependency.
What you need to do:
- React 18 or 19 consumers: no runtime code changes are expected for this peer dependency
update. - React 16 or 17 consumers: stay on visx 3 or upgrade your app to React 18+ before installing
visx 4. - Preact consumers: continue aliasing
reactandreact-domtopreact/compat, and configure
your package manager to satisfy the React 18/19 peer dependency range.
TypeScript React types are peer dependencies
React-based @visx/* packages now declare @types/react as an optional peer dependency instead of
bundling their own copy. Packages that touch React DOM APIs also declare optional @types/react-dom
peer dependencies.
What you need to do:
- TypeScript consumers: install
@types/reactand, when needed,@types/react-domusing the
major version that matches your React version. - Non-TypeScript consumers: no action needed.
Runtime PropTypes were removed
visx packages no longer depend on prop-types, and the build no longer generates runtimeComponent.propTypes from TypeScript definitions.
What you need to do:
- Most consumers do not need to change code.
- If your app imported
prop-typesonly because a visx package installed it transitively, addprop-typesas a direct dependency. - If your app inspects visx component
propTypesat runtime, migrate that validation into your app
or use TypeScript/static checks instead.
Package root imports are the supported API surface
Every package now publishes an exports field mapping package-root imports to types, import,
and require entries. This improves module resolution in modern bundlers and Node.js, but it also
restricts access to internal paths.
What you need to do: replace deep imports like @visx/foo/lib/bar with package-root imports
like @visx/foo. If a symbol you need is not exported from the package root, open an issue.
Most common component prop types are now exported from package roots as TypeScript-only exports. For
example, prefer importing AxisProps from @visx/axis instead of reaching into internal files.
Modern browser targets
Babel targets were bumped to modern browsers. IE11 and other legacy browsers are no longer
supported.
What you need to do: if you still need IE11, stay on visx 3.
Published ESM output works in strict ESM environments
The published esm/ output now emits explicit .js extensions on relative imports and a nestedesm/package.json with "type": "module". Strict Node ESM consumers such as Vite SSR, Deno, and
edge runtimes should no longer hit ERR_MODULE_NOT_FOUND from extensionless visx ESM imports.
What you need to do: nothing, unless you previously pinned to an older alpha to work around ESM
issues. Upgrade all visx packages to ^4.0.0.
D3 shape and path dependencies were upgraded
visx packages now use d3-shape v3 and d3-path v3 through @visx/vendor. visx preserves its
existing package-level behavior where compatibility shims were needed, but direct D3 imports are now
your app's responsibility.
What you need to do:
- Most consumers do not need to change code.
- If your app imports
d3-shapeord3-pathwithout declaring them in your ownpackage.json, add
them as direct dependencies. - If your app imports from
@visx/vendor/d3-shapeor@visx/vendor/d3-path, review the D3 v3 API
and type changes.
`@visx/bounds` `withBoundingRects` requires `nodeRef`
withBoundingRects no longer falls back to ReactDOM.findDOMNode. The wrapped component receives anodeRef prop and must attach it to the DOM element that should be measured. This keeps@visx/bounds compatible with React 19 and React strict-mode expectations.
What you need to do:
- If you use
withBoundingRects, make sure the wrapped component acceptsnodeRefand passes it to
the measured DOM element. - If you use TypeScript, type
nodeRefas a React ref for the element you measure. - If you already attach
nodeRef, no action is needed.
- function Tooltip({ rect, parentRect, children }) {
- return <div>{children}</div>;
+ type TooltipProps = Omit<WithBoundingRectsProps, 'nodeRef'> & {
+ nodeRef?: React.Ref<HTMLDivElement>;
+ };
+
+ function Tooltip({ rect, parentRect, nodeRef, children }: TooltipProps) {
+ return <div ref={nodeRef}>{children}</div>;
}`@visx/responsive` measurement fixes
ParentSize and withParentSize now render a two-div structure to prevent infinite height growth
in flex and grid layouts. useParentSize now uses a callback ref internally and also accepts an
optional externalRef.
What you need to do:
- Most consumers do not need to change code.
- If you access
parentRef.currentfromuseParentSize, replace it with the returnednode. - If tests or CSS rely on the exact
ParentSizewrapper DOM structure, update them for the nested
measurement div.
`@visx/xychart` axis loading behavior
BaseAxis no longer renders until at least one data series with non-empty data has been
registered in DataContext. Previously, on initial render the axis could use the fallbackscaleLinear() domain [0, 1], causing tickFormat to receive incorrect intermediate values
before real data loaded.
What you need to do:
- Most consumers do not need to change code.
- If you relied on the axis being visible before data loaded, render a placeholder
<Axis />from@visx/axisdirectly with your own scale until your data is ready, then switch to the xychart<Axis />.
`@visx/xychart` `withRegisteredData` was removed
The internal withRegisteredData enhancer was removed from @visx/xychart. Series components now
register their data directly instead of using that higher-order component.
What you need to do: most consumers do not need to change code. If you imported@visx/xychart/lib/enhancers/withRegisteredData directly, migrate to the public xychart series
components and package-root exports.
Lodash is no longer a transitive implementation dependency
@visx/responsive, @visx/text, @visx/xychart, and @visx/shape no longer declare directlodash or @types/lodash dependencies. Internal debounce, memoize, and chunk usage has been
replaced with small local helpers. Public visx APIs are intended to behave the same.
What you need to do: if your app imported lodash without declaring it in your ownpackage.json, add lodash as a direct dependency. It may have worked before only because a visx
package installed it transitively.
Building visx from source requires newer tooling
This note is for contributors or consumers building the visx repo itself. The repository now uses
Yarn 4 via Corepack and requires Node 24 or newer.
What you need to do: if you only install published @visx/* packages, no action is needed. If
you build the repo locally, use Node 24+ and run Yarn through Corepack.
From 4.0.0 alpha releases
Upgrade all @visx/* packages to ^4.0.0. The stable release includes all alpha changes listed
below, plus the final React 18/19 peer dependency range and Dependabot cleanup from the final alpha
publishes.
If you installed 4.0.0-alpha.10, 4.0.0-alpha.12, or 4.0.0-alpha.13, upgrade immediately. Those
alpha releases partially failed and left some packages unpublished or out of sync.
Alpha release history
The notes below are preserved for users who tested the v4 alpha series. Stable upgrade guidance
above supersedes any older alpha-specific instructions.
4.0.0-alpha.17
Internal only: updated transitive brace-expansion lockfile entries to resolve a Dependabot
security alert. No consumer-facing visx API changes are expected.
4.0.0-alpha.16
Internal only: updated demo, test, release, and build-tool dependencies to resolve Dependabot
security alerts. No consumer-facing visx API changes are expected.
4.0.0-alpha.15
React 18 or 19 is now required
React-based @visx/* packages now declare react peer dependencies as ^18.0.0 || ^19.0.0.
Packages that depend on react-dom declare the same supported range for their react-dom peer
dependency. Optional @types/react and, where applicable, @types/react-dom peer dependencies use
the same supported major-version range.
What you need to do:
- React 18 or 19 consumers: no runtime code changes are expected for this peer dependency
update. - React 16 or 17 consumers: stay on visx v3 or upgrade your app to React 18+ before installing
visx v4. - TypeScript consumers: install
@types/reactand, when needed,@types/react-domusing the
major version that matches your React version. - Preact consumers: continue aliasing
reactandreact-domtopreact/compat, and configure
your package manager to satisfy the React 18/19 peer dependency range.
4.0.0-alpha.14
Re-publish of alpha.12 and alpha.13, which partially failed (see below). No intended code changes
relative to alpha.12 — all packages are now published at the same version.
What you need to do: if you installed any @visx/* packages at 4.0.0-alpha.12 or4.0.0-alpha.13, upgrade to alpha.14 to ensure all packages are in sync.
Lodash removed from package dependencies
@visx/responsive, @visx/text, @visx/xychart, and @visx/shape no longer declare directlodash or @types/lodash dependencies. Internal debounce, memoize, and chunk usage has been
replaced with small local helpers. Public visx APIs are intended to behave the same, including the
existing debounce options in @visx/responsive.
What you need to do:
- Most consumers: nothing — this removes an implementation dependency from visx packages.
- If your app imported
lodashwithout declaring it in your ownpackage.json: addlodashas
a direct dependency. It may have worked before only because a visx package installed it
transitively.
This release also fixes the XYChart docs/demo example so it passes its known width into XYChart.
No consumer code changes are needed for that docs-only fix.
4.0.0-alpha.13 (broken)
⚠️ Do not use this release. An npm provenance transparency log conflict caused lerna publish
to fail partway through. Some packages were never published at this version while the rest were,
resulting in a version mismatch across the monorepo. Use alpha.14 instead.
4.0.0-alpha.12 (broken)
⚠️ Do not use this release. An npm provenance transparency log conflict caused lerna publish
to fail partway through. Some packages were never published at this version while the rest were,
resulting in a version mismatch across the monorepo. Use alpha.14 instead.
4.0.0-alpha.11
Re-publish of alpha.10 which partially failed (see below). No code changes — all packages are now
published at the same version.
What you need to do: if you installed any @visx/* packages at 4.0.0-alpha.10, upgrade toalpha.11 to ensure all packages are in sync.
4.0.0-alpha.10 (broken)
⚠️ Do not use this release. A sigstore transparency log conflict caused lerna publish to fail
partway through. 18 packages were never published at this version while the rest were, resulting in
a version mismatch across the monorepo. Use alpha.11 instead.
4.0.0-alpha.9
ESM fix now published for all packages
Five packages (@visx/vendor, @visx/point, @visx/scale, @visx/curve, @visx/mock-data) were
stuck on pre-alpha.2 versions and still shipped ESM output without .js extensions or theesm/package.json "type": "module" marker. This release force-publishes every package so the
alpha.2 ESM fix (#1976) is present across the board.
What you need to do: if you hit ERR_MODULE_NOT_FOUND in strict ESM environments (Vite SSR,
Deno, edge runtimes) with any of those five packages, upgrading to this release resolves it.
4.0.0-alpha.8
`@visx/responsive` useParentSize external ref support
useParentSize now accepts an optional externalRef in its config object. If provided, the hook
forwards the observed DOM node to both its internal state and the external ref, eliminating the need
for a wrapper div when you already have a ref on the container element.
const myRef = useRef<HTMLDivElement>(null);
const { parentRef, width, height } = useParentSize({ externalRef: myRef });
return <div ref={parentRef}>...</div>;
// myRef.current is also set to the div elementBoth RefObject and callback refs are supported.
What you need to do:
- Most consumers: nothing — this is an additive, non-breaking change. Existing usage without an
externalRefargument is unchanged. - If you were adding a wrapper div to combine your own ref with
parentRef: you can now remove
the wrapper and pass your ref directly via theexternalRefoption.
4.0.0-alpha.7
`@visx/responsive` ParentSize flex/grid infinite growth fix
ParentSize and withParentSize now render a two-div structure to prevent infinite height growth
in flex and grid layouts (#881,
#1014).
Previously, the component rendered a single wrapper ``. In
flex or grid containers, a child SVG's intrinsic height could grow the wrapper, triggering
ResizeObserver in a feedback loop.
The new structure uses an outer and an inner
that holds the ResizeObserver and children. Since the inner div is absolutely positioned, children's
intrinsic sizes cannot grow the outer container.
What you need to do:
- Most consumers: nothing — the component API is unchanged and the visual result should be
identical or better (no more infinite growth). - If you rely on the wrapper div's exact DOM structure (e.g., querying it in tests or applying
CSS that targets a single wrapper div): the wrapper is now two nested divs.className,style,
and all other HTML attributes still apply to the outer div. - If you use the deprecated
parentSizeStylesprop: it still works and applies to the outer
div, butposition: relativeis prepended to ensure the inner absolutely-positioned measurement
div works correctly. If you explicitly setpositionin your custom styles, your value takes
precedence. - If you use
withParentSize: the same two-div structure applies. The container div is no
longer a single ``.
4.0.0-alpha.6
`@visx/responsive` useParentSize callback ref fix
useParentSize now uses a callback ref internally instead of useRef. This fixes a bug where the
hook could permanently report 0×0 dimensions because parentRef.current was null when theuseEffect first ran, and the dependency array never re-fired once the ref attached to the DOM
(#1816).
The returned parentRef is now a callback ref ((node: T | null) => void) instead of aRefObject<T | null>. A new node property is also returned for direct access to the observed DOM
element.
What you need to do:
Most consumers: nothing — `` works with both
RefObjectand callback
refs, andParentSizecomponent users are unaffected.If you access
parentRef.currentdirectly: replace with the newnodereturn value.diff- const { parentRef, width, height } = useParentSize(); - console.log(parentRef.current); + const { parentRef, node, width, height } = useParentSize(); + console.log(node);
4.0.0-alpha.5
`@visx/xychart` axis rendering fix (breaking)
BaseAxis no longer renders until at least one data series with non-empty data has been
registered in DataContext. Previously, on initial render the axis could use the fallbackscaleLinear() domain [0, 1], causing tickFormat to receive incorrect intermediate values
before real data loaded (#1975).
This is a behavior change: axes that previously rendered immediately (showing 0–1 ticks while
data was loading) will now render null until real data is available.
What you need to do:
- Most consumers: nothing — this is a bugfix. If you were working around stale tick labels on
first render, you can remove that workaround. - If you relied on the axis being visible before data loaded (e.g., to display a skeleton axis):
render a placeholder<Axis />from@visx/axisdirectly with your own scale until your data is
ready, then switch to the xychart<Axis />.
Thank you wildseansy for the fix
#1979
4.0.0-alpha.4
Internal only: replaced ts-node with tsx (esbuild-based) for faster TypeScript script execution.
No consumer-facing changes.
4.0.0-alpha.3
`@types/react` and `@types/react-dom` as peer dependencies
React-based @visx/* packages now declare @types/react as a peer dependency instead of
bundling their own copy. That way your app supplies a single version and you avoid duplicate or
conflicting installs.
@visx/bounds, @visx/tooltip, @visx/xychart, and the @visx/visx meta-package all declare@types/react-dom as an optional peer directly (bounds and tooltip type DOM-touching APIs; xychart
consumes tooltip and so transitively needs react-dom at runtime; the umbrella matches the pattern of
its DOM-touching members).
@visx/brush and @visx/wordcloud also declare @types/react as an optional peer so consumers
installing either package directly get the same type-dependency signal as the rest of the
React-based @visx/* packages.
The peers are marked optional via peerDependenciesMeta, so non-TypeScript consumers will not see
missing-peer warnings.
What you need to do:
React 18 or 19 (TypeScript users): add
@types/reactas a dev dependency matching your React
version:bashyarn add -D @types/reactIf you use
@visx/bounds,@visx/tooltip,@visx/xychart, or the@visx/visxmeta-package,
also install@types/react-dom:bashyarn add -D @types/react-domUse the major versions that align with your
react/react-domversions.Non-TypeScript consumers: no action needed.
If you see TypeScript errors about missing react types after upgrading, install the appropriate@types/react (and @types/react-dom when using @visx/bounds, @visx/tooltip, @visx/xychart,
or @visx/visx) in your application.
4.0.0-alpha.2
Node ESM compatibility fix for published `esm/` output
The published esm/ output now emits explicit .js extensions on relative imports and a nestedesm/package.json with "type": "module". Strict Node ESM consumers (Vite/react-router SSR, Deno,
edge runtimes) previously failed with ERR_MODULE_NOT_FOUND when resolving visx's ESM entry.
What you need to do: nothing — this is a bugfix. If you were pinned to 4.0.0-alpha.1
specifically to avoid a different ESM issue, you can upgrade safely.
4.0.0-alpha.1
Release-plumbing only: prerelease bump configuration and CI permissions for release PR comments. No
consumer-facing changes.
4.0.0-alpha.0
The React 19 cut. This is the release that drops legacy React support and modernizes the build
targets.
React 19 support (automatic JSX transform)
Every @visx/* package now uses the automatic JSX transform and imports React symbols as direct
named imports or type-only imports (no more React.ReactNode namespace access). Peer dependency
ranges were widened to ^16.14.0 || ^17.0.0-0 || ^18.0.0-0 || ^19.0.0-0.
What you need to do:
- React 19 consumers: you should be able to upgrade with no code changes.
- React 18 / 17 / 16.14+ consumers: still supported, no action needed.
- React ≤ 16.13: no longer supported — upgrade React first.
- If you import directly from deep subpaths (e.g.
@visx/shape/lib/shapes/Bar), prefer the package
root (@visx/shape). Deep imports are no longer the blessed API surface and may break in a future
alpha. Every package now declaresexportsso Node's module resolver will honor the root entry.
Dropped IE11 support
Babel targets were bumped to modern browsers. IE11 and other legacy browsers are no longer
supported.
What you need to do: if you still need IE11, stay on 3.x.
Package `exports` field
Every package now publishes an exports field mapping . to types, import, and require
entries. This improves module resolution in modern bundlers and Node.js, but does restrict access to
internal paths.
What you need to do: replace any deep imports (@visx/foo/lib/bar) with root imports
(@visx/foo). If a symbol you need isn't re-exported from the root, open an issue.
Lerna v9 / OIDC publishing / resolution cleanup
Internal only — Lerna was upgraded to v9, publishing now uses OIDC trusted publishing, and unusedansi-* resolutions were removed from the root. No consumer impact.
`@visx/demo` (internal)
Upgraded to React 19, Next.js 15, and @react-spring/web v10. Affects contributors only.
File: package.json
{
"name": "@visx/root",
"license": "MIT",
"version": "0.0.0",
"description": "Low-level visualization components",
"keywords": [
"react",
"d3",
"visualization",
"visx",
"charts"
],
"engines": {
"node": ">=24.0.0",
"yarn": ">=4.0.0"
},
"contributors": [
{
"name": "Harrison Shoff",
"url": "https://github.com/hshoff"
},
{
"name": "Chris Williams",
"url": "https://github.com/williaster"
},
{
"name": "Krist Wongsuphasawat",
"url": "https://github.com/kristw"
}
],
"private": true,
"scripts": {
"build:vendor": "yarn run ts ./packages/visx-vendor/scripts/buildVendor",
"babel": "yarn run babel:cjs && yarn run babel:esm",
"babel:cjs": "lerna exec --ignore '@visx/{demo,vendor}' --parallel -- 'babel --root-mode upward --delete-dir-on-start src/ --out-dir lib --extensions .ts,.tsx'",
"babel:esm": "ESM=true lerna exec --ignore '@visx/{demo,vendor}' --parallel -- 'babel --root-mode upward --delete-dir-on-start src/ --out-dir esm --extensions .ts,.tsx' && node ./scripts/writeEsmPackageJson.js",
"babel:pkg": "lerna exec --scope $PKG -- 'babel --root-mode upward --delete-dir-on-start src/ --out-dir lib --extensions .ts,.tsx' && lerna exec --scope $PKG -- 'ESM=true babel --root-mode upward --delete-dir-on-start src/ --out-dir esm --extensions .ts,.tsx' && node ./scripts/writeEsmPackageJson.js",
"build": "yarn run build:vendor && yarn run babel && yarn run type && yarn run type:kernel-api",
"build:sizes": "yarn run ts ./scripts/computeBuildSizes.ts",
"build:release": "yarn run ts ./scripts/performRelease/index.ts",
"dev:demo": "yarn run docs:generate && yarn workspace @visx/demo dev",
"check:sizes": "yarn run ts ./scripts/compareBuildSizes.ts",
"clean": "rm -rf ./packages/**/{lib,esm}",
"docs:generate": "yarn run ts ./scripts/generateDocs.ts",
"format": "lerna exec --parallel -- 'prettier --write --ignore-path ../../.prettierignore .'",
"lint": "eslint packages/ --quiet",
"lint:fix": "yarn run lint --fix",
"postinstall": "yarn run ts ./scripts/postInstall.ts",
"prepare-release": "git checkout master && git pull --rebase origin master && lerna updated",
"release": "yarn run prepare-release && lerna publish --exact",
"setup": "yarn run build",
"test": "yarn run vitest run",
"test:watch": "yarn run vitest watch",
"vitest": "vitest",
"vitest:ui": "vitest --ui",
"registry:smoke": "yarn workspace @visx/registry smoke:install",
"registry:validate": "yarn workspace @visx/registry validate",
"ts": "tsx --tsconfig ./tsconfig.node.json",
"type": "yarn type:clean && yarn type:build",
"type:build": "lerna exec -- 'tsc --build'",
"type:kernel-api": "tsc -p packages/visx-kernel/test/tsconfig.typecheck.json --pretty false",
"type:clean": "find . -type f -name 'tsconfig.tsbuildinfo' -delete",
"type:pkg": "lerna exec --scope $PKG -- 'tsc --build --verbose'",
"type:update-refs": "yarn run ts ./scripts/updateTsReferences.ts",
"vendor-check": "yarn run ts ./packages/visx-vendor/scripts/flagVendorRequirements.ts"
},
"devDependencies": {
"@babel/cli": "^7.26.4",
"@babel/core": "^7.26.0",
"@babel/eslint-parser": "^7.25.9",
"@babel/preset-env": "^7.29.7",
"@babel/preset-react": "^7.26.3",
"@babel/preset-typescript": "^7.26.0",
"@octokit/openapi-types": "18.0.0",
"@octokit/rest": "18.1.0",
"@testing-library/dom": "^10.4.0",
"@testing-library/jest-dom": "^6.6.0",
"@testing-library/react": "^16.1.0",
"@testing-library/user-event": "^13.5.0",
"@types/jsdom": "27.0.0",
"@types/node": "^22.10.2",
"@types/react": "^19.0.0",
"@types/react-dom": "^19.0.0",
"@typescript-eslint/eslint-plugin": "^8.18.1",
"@typescript-eslint/parser": "^8.18.1",
"@vitest/coverage-v8": "4.1.8",
"@vitest/eslint-plugin": "^1.4.0",
"@vitest/ui": "4.1.8",
"airbnb-js-shims": "^2.2.1",
"babel-plugin-add-import-extension": "^1.6.0",
"chalk": "4.1.0",
"eslint": "^8.57.0",
"eslint-config-airbnb": "^19.0.4",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-jsx-a11y": "^6.6.1",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-promise": "^6.1.1",
"eslint-plugin-react": "^7.31.11",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-unicorn": "^45.0.2",
"fast-glob": "3.2.5",
"filesize": "6.1.0",
"jsdom": "27.0.0",
"lerna": "^9.0.7",
"prettier": "^2.8.1",
"react": "^18.0.0 || ^19.0.0",
"react-dom": "^18.0.0 || ^19.0.0",
"timezone-mock": "^1.1.0",
"tsx": "^4.19.0",
"typescript": "^5.7.0",
"vitest": "4.1.8"
},
"packageManager": "[email protected]",
"workspaces": {
"packages": [
"./packages/*"
]
},
"resolutions": {
"react": "^19.0.0",
"react-dom": "^19.0.0",
"@types/react": "^19.0.0",
"@types/react-dom": "^19.0.0",
"postcss@npm:8.4.31": "8.5.15",
"caniuse-lite": "^1.0.30001787",
"baseline-browser-mapping": "^2.10.18"
}
}
File: PULL_REQUEST_TEMPLATE.md
:boom: Breaking Changes
:rocket: Enhancements
:memo: Documentation
:bug: Bug Fix
:house: Internal
File: registry.json
{
"$schema": "https://ui.shadcn.com/schema/registry.json",
"name": "visx",
"homepage": "https://github.com/airbnb/visx",
"include": ["packages/visx-registry/registry.json"]
}
File: tsconfig.eslint.json
{
"extends": "./tsconfig.options.json",
"include": [
"scripts//",
"packages//src//",
"packages//test//",
"packages//types//",
"packages//scripts//",
"packages//registry//",
"vitest.workspace.ts",
"packages//vitest.config.ts"
]
}
File: tsconfig.json
{
"extends": "./tsconfig.options.json",
"files": [],
}
File: tsconfig.node.json
{
"compilerOptions": {
"allowSyntheticDefaultImports": true,
"composite": true,
"declaration": true,
"declarationMap": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"isolatedModules": false,
"jsx": "react",
"lib": ["dom", "esnext"],
"module": "commonjs",
"moduleResolution": "node",
"noEmitOnError": true,
"noErrorTruncation": false,
"noImplicitReturns": true,
"noUnusedLocals": true,
"pretty": true,
"removeComments": false,
"resolveJsonModule": true,
"strict": true,
"target": "es2015",
"typeRoots": ["./node_modules/@types", "./types"],
"useDefineForClassFields": false
}
}
File: tsconfig.options.json
{
"compilerOptions": {
"allowSyntheticDefaultImports": true,
"declaration": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"isolatedModules": false,
"jsx": "react-jsx",
"lib": [
"dom",
"esnext"
],
"module": "esnext",
"moduleResolution": "node",
"noEmitOnError": true,
"noImplicitReturns": true,
"noUnusedLocals": true,
"pretty": true,
"removeComments": false,
"strict": true,
"target": "es2015",
"useDefineForClassFields": false,
"composite": true,
"declarationMap": true,
"emitDeclarationOnly": true,
"resolveJsonModule": true
}
}
File: .yarnrc.yml
enableGlobalCache: false
nodeLinker: node-modules
logFilters:
- pattern: "* doesn't provide react ()"
level: "discard" - pattern: "* doesn't provide react-dom ()"
level: "discard" - pattern: "* doesn't provide @react-spring/web ()"
level: "discard" - pattern: "* doesn't provide webpack ()"
level: "discard" - pattern: "Some peer dependencies are incorrectly met*"
level: "discard"
File: packages/sizes.json
{"visx-a11y":{"esm":28466,"lib":34549},"visx-annotation":{"esm":19693,"lib":23755},"visx-axis":{"esm":14072,"lib":19318},"visx-bounds":{"esm":1495,"lib":1915},"visx-brush":{"esm":42024,"lib":44001},"visx-chart":{"esm":5680,"lib":8613},"visx-chord":{"esm":1907,"lib":2683},"visx-clip-path":{"esm":1522,"lib":2713},"visx-curve":{"esm":351,"lib":2594},"visx-delaunay":{"esm":1475,"lib":2489},"visx-demo":{"esm":0,"lib":0},"visx-drag":{"esm":9078,"lib":11025},"visx-event":{"esm":3571,"lib":5257},"visx-geo":{"esm":8104,"lib":11674},"visx-glyph":{"esm":7243,"lib":11421},"visx-gradient":{"esm":6928,"lib":11581},"visx-grid":{"esm":9631,"lib":12892},"visx-group":{"esm":502,"lib":1030},"visx-heatmap":{"esm":3496,"lib":4564},"visx-hierarchy":{"esm":8687,"lib":13458},"visx-kernel":{"esm":12168,"lib":15402},"visx-legend":{"esm":14929,"lib":20754},"visx-marker":{"esm":3855,"lib":6120},"visx-mock-data":{"esm":325698,"lib":330728},"visx-network":{"esm":3088,"lib":5105},"visx-pattern":{"esm":7400,"lib":10317},"visx-point":{"esm":791,"lib":1901},"visx-react-spring":{"esm":8724,"lib":11009},"visx-registry":{"esm":116,"lib":79},"visx-responsive":{"esm":11775,"lib":14019},"visx-sankey":{"esm":2501,"lib":3894},"visx-scale":{"esm":19357,"lib":31820},"visx-shape":{"esm":52847,"lib":76176},"visx-stats":{"esm":9258,"lib":10690},"visx-text":{"esm":6416,"lib":7990},"visx-theme":{"esm":22587,"lib":31584},"visx-threshold":{"esm":2067,"lib":2758},"visx-tooltip":{"esm":38153,"lib":46550},"visx-vendor":{"esm":2974,"lib":3226},"visx-visx":{"esm":1718,"lib":4399},"visx-voronoi":{"esm":1909,"lib":3235},"visx-wordcloud":{"esm":1996,"lib":2995},"visx-xychart":{"esm":126022,"lib":155810},"visx-zoom":{"esm":12508,"lib":14835}}
File: packages/visx-a11y/Readme.md
@visx/a11y
Accessibility helpers for primitive visx charts without changing the low-level visx primitive model.
The package is split into server-safe entries for generated semantics and a client React entry for
hooks and companion components.
Installation
npm install --save @visx/a11yMotivation
visx is intentionally low level: primitives take props, compose freely, and stay out of your app's
state model. That is what makes visx useful for unusual charts, custom dashboards, and product
interfaces that do not fit a fixed charting API.
The tradeoff is that primitive charts tend to rebuild the same accessibility layer:
- chart titles and long descriptions
- series labels and point value labels
- hidden data tables for exact values
- live regions for async chart updates
- keyboard affordances for chart exploration
- rules for hiding decorative SVG chrome
That works for one chart. It gets noisy when a registry or dashboard has many charts built from
different visx packages. Small differences creep in, dense charts can produce too much screen reader
output, and teams end up copying local helpers from chart to chart.
@visx/a11y gives those charts a shared semantic layer while keeping the rendering primitives
plain. It does not ship a chart component, impose SVG structure, or hide non-data elements
automatically. Instead, it gives you spreadable props, generated descriptions, table fallbacks, and
small React helpers that you can attach to the primitives you already render.
Primitive-first design
The a11y package is a semantics layer, not a chart framework.
- visx primitives remain prop-driven.
- Server helpers are pure functions with no DOM or React hook requirements.
- The client hook uses React
useId()only whenidis omitted. - Consumers own the SVG render tree, focus ring styling, and decorative element visibility.
- Data table and announcer components are independently usable.
- Dense charts degrade to summary descriptions above
pointDescriptionThreshold. keyboardNavEnabledcontrols roving focus for point-by-point chart exploration.
This keeps chart registry items and product charts able to opt in one layer at a time. If a chart
needs custom descriptions, a visible data table, a separate live region, or no interactive keyboard
state yet, the primitive API still supports that.
Basic usage
Use the server entry when a server-rendered chart only needs generated SVG semantics, a text
description, or an HTML table fallback.
import type { ChartA11yConfig } from '@visx/a11y/server';
import {
generateChartDescription,
generateDataTableHTML,
getChartAriaProps,
} from '@visx/a11y/server';
type Datum = {
month: string;
revenue: number;
};
const config: ChartA11yConfig<Datum> = {
id: 'revenue-chart',
title: 'Revenue by month',
chartType: 'line',
data,
x: (datum) => datum.month,
y: (datum) => datum.revenue,
yLabel: 'Revenue',
formatY: (value) => `$${value}`,
};
const a11y = getChartAriaProps(config);
const description = generateChartDescription(config);
const tableHtml = generateDataTableHTML(config);Use useChartA11y from the React entry when chart components need React-bound props and companion
components.
'use client';
import { useChartA11y } from '@visx/a11y/react';
export function RevenueChart({ data }) {
const a11y = useChartA11y({
id: 'revenue-chart',
title: 'Revenue by month',
chartType: 'line',
data,
x: (datum) => datum.month,
y: (datum) => datum.revenue,
yLabel: 'Revenue',
formatY: (value) => `$${value}`,
});
return (
<>
<svg {...a11y.svgProps} id={a11y.id}>
<desc id={a11y.descriptionId}>{a11y.description}</desc>
{/* chart marks */}
</svg>
<a11y.DataTable />
<a11y.Announcer />
</>
);
}Recipes
Level 1: Chart semantics, description, and table fallback
Start by spreading svgProps, rendering the generated description, and adding the pre-bound data
table and live announcer. This gives the chart an accessible name, a chart-level description, and an
exact-value table fallback without changing the visual chart.
const a11y = useChartA11y({
id: 'revenue-chart',
title: 'Revenue by month',
chartType: 'line',
data,
x: (datum) => datum.month,
y: (datum) => datum.revenue,
yLabel: 'Revenue',
formatY: (value) => `$${value}`,
});
return (
<>
<svg {...a11y.svgProps} id={a11y.id}>
<desc id={a11y.descriptionId}>{a11y.description}</desc>
<g>
{data.map((datum) => (
<circle key={datum.month} />
))}
</g>
</svg>
<a11y.DataTable />
<a11y.Announcer />
</>
);Level 2: Series and point semantics
After Level 1 is in place, spread getSeriesProps on each rendered series group and getPointProps
on each rendered data mark. This adds per-series labels and per-point value labels for charts below
the configured pointDescriptionThreshold.
const a11y = useChartA11y({
id: 'revenue-chart',
title: 'Revenue by month',
chartType: 'line',
data,
x: (datum) => datum.month,
y: (datum) => datum.revenue,
yLabel: 'Revenue',
formatY: (value) => `$${value}`,
series: [{ label: 'Revenue' }],
});
return (
<>
<svg {...a11y.svgProps} id={a11y.id}>
<desc id={a11y.descriptionId}>{a11y.description}</desc>
<g {...a11y.getSeriesProps(0)}>
{data.map((datum, index) => (
<circle key={datum.month} {...a11y.getPointProps(0, index)} />
))}
</g>
</svg>
<a11y.DataTable />
<a11y.Announcer />
</>
);Level 3: Keyboard navigation and tooltip bridge
Keep keyboardNavEnabled enabled when a chart should support point-by-point keyboard exploration.useChartA11y adds roving focus props to each data mark and calls onPointFocus when keyboard
focus moves to a point. Use that callback to mirror the same tooltip, crosshair, or active-point
state that pointer interaction uses.
const a11y = useChartA11y({
id: 'revenue-chart',
title: 'Revenue by month',
chartType: 'line',
data,
x: (datum) => datum.month,
y: (datum) => datum.revenue,
yLabel: 'Revenue',
formatY: (value) => `$${value}`,
series: [{ label: 'Revenue' }],
onPointFocus: ({ datum, index, seriesIndex }) => {
showTooltip({
datum,
index,
seriesIndex,
});
},
});
return (
<svg {...a11y.svgProps} id={a11y.id}>
<desc id={a11y.descriptionId}>{a11y.description}</desc>
<g {...a11y.getSeriesProps(0)}>
{data.map((datum, index) => (
<circle
key={datum.month}
className={a11y.focusedPoint?.index === index ? 'is-keyboard-focused' : undefined}
{...a11y.getPointProps(0, index)}
/>
))}
</g>
</svg>
);Use useChartKeyboardNav directly when a custom chart already owns its generated ARIA semantics but
still wants the same roving-focus behavior, point focus state, and onPointFocus callback.
Keyboard interaction model
When keyboard navigation is enabled, useChartA11y starts in chart mode. The chart root is
tabbable, and data marks become tabbable only while keyboard exploration is active. Navigation is
enabled by default for charts with at least one point and no more than pointDescriptionThreshold
points.
| Key | Result |
|---|---|
Tab |
Moves focus to or away from the chart root through normal page tab order. |
Enter or Space |
Enters data mode and focuses the first data point, or the last focused point when returning. |
ArrowRight |
Moves to the next point in the current series, wrapping at the end. |
ArrowLeft |
Moves to the previous point in the current series, wrapping at the beginning. |
ArrowDown |
Moves to the next non-empty series and keeps the closest point index. |
ArrowUp |
Moves to the previous non-empty series and keeps the closest point index. |
Home |
Moves to the first point in the current series. |
End |
Moves to the last point in the current series. |
Control + Home |
Moves to the first point in the chart. |
Control + End |
Moves to the last point in the chart. |
Escape |
Exits data mode and returns focus to the chart root. |
? or F1 |
Announces the configured keyboard help text through Announcer. |
Decorative chart chrome
@visx/a11y annotates the chart elements it receives through the hook. Consumers are responsible
for hiding decorative chart chrome from assistive technology. Grid lines, axis ticks, background
rects, clipping helpers, and other non-data elements should usually be rendered witharia-hidden="true" so screen readers focus on the title, description, series, points, and data
table.
<svg {...a11y.svgProps} id={a11y.id}>
<rect aria-hidden="true" width={width} height={height} />
<GridRows aria-hidden="true" scale={yScale} width={innerWidth} />
<AxisBottom aria-hidden="true" scale={xScale} />
<g {...a11y.getSeriesProps(0)}>{/* data marks */}</g>
</svg>File: packages/visx-a11y/package.json
{
"name": "@visx/a11y",
"version": "4.0.0",
"description": "visx chart accessibility helpers",
"sideEffects": false,
"main": "lib/index.js",
"module": "esm/index.js",
"types": "lib/index.d.ts",
"exports": {
".": {
"types": "./lib/index.d.ts",
"import": "./esm/index.js",
"require": "./lib/index.js"
},
"./react": {
"types": "./lib/react/index.d.ts",
"import": "./esm/react/index.js",
"require": "./lib/react/index.js"
},
"./server": {
"types": "./lib/server.d.ts",
"import": "./esm/server.js",
"require": "./lib/server.js"
}
},
"files": [
"lib",
"esm"
],
"repository": {
"type": "git",
"url": "git+https://github.com/airbnb/visx.git"
},
"keywords": [
"visx",
"react",
"visualizations",
"charts",
"accessibility",
"a11y"
],
"author": "@hshoff",
"license": "MIT",
"bugs": {
"url": "https://github.com/airbnb/visx/issues"
},
"homepage": "https://github.com/airbnb/visx#readme",
"peerDependencies": {
"@types/react": "^18.0.0 || ^19.0.0",
"react": "^18.0.0 || ^19.0.0"
},
"publishConfig": {
"access": "public"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
},
"devDependencies": {
"@types/react": "^19.0.0"
}
}
File: packages/visx-a11y/tsconfig.json
{
"compilerOptions": {
"declarationDir": "lib",
"outDir": "lib",
"rootDir": "src"
},
"exclude": [
"lib",
"test"
],
"extends": "../../tsconfig.options.json",
"include": [
"src//*",
"types//",
"../../types/**/"
],
"references": []
}
File: packages/visx-annotation/Readme.md
@visx/annotation
SVG Annotations enable you to label points, thresholds, or regions of a visualization to provide
additional context to for your chart consumer. This package is heavily inspired by
Susie Lu'sreact-annotation library.
Each annotation consists of three (optional) parts:
Subject(CircleSubject,LineSubject, more 🔜) – what part of a chart is being annotated
(point, line, region)Label– the text component for the annotation. Handles SVG text wrapping using@visx/text,
and supportstitleandsubtitlecustomization as well as vertical & horizontal anchors /
alignmentConnector– line connecting a subject and label
The Annotation or EditableAnnotation component wrappers allow you to compose these components
and simplify their individual positioning:
<EditableAnnotation
x={subjectX}
y={subjectY}
dx={labelDx} // x offset of label from subject
dy={labelDy} // y offset of label from subject
onDragEnd={({ x, y, dx, dy }) => ...}
>
<Connector />
<CircleSubject />
<Label title="Context about this point" subtitle="More deets">
</EditableAnnotation>Components can also be used in isolation, in which case you must specify exact positions for each
item:
() => (
<g>
<Connector x={subjectX} y={subjectY} dx={labelDx} dy={labelDy} />
<CircleSubject x={subjectX} y={subjectY} />
<Label x={subjectX + labelDx} y={subjectY + labelDy} title="...">
</g>
)⚠️ `ResizeObserver` dependency
The Label component relies on ResizeObservers for auto-sizing. If you need a polyfill, you can
either polute the window object or inject it cleanly through props:
import { ResizeObserver } from 'your-favorite-polyfill';
function App() {
return <Label resizeObserverPolyfill={ResizeObserver} {...} />Installation
npm install --save @visx/annotationFile: packages/visx-annotation/package.json
{
"name": "@visx/annotation",
"version": "4.0.0",
"description": "visx annotation",
"sideEffects": false,
"main": "lib/index.js",
"module": "esm/index.js",
"types": "lib/index.d.ts",
"exports": {
".": {
"types": "./lib/index.d.ts",
"import": "./esm/index.js",
"require": "./lib/index.js"
}
},
"files": [
"lib",
"esm"
],
"repository": {
"type": "git",
"url": "git+https://github.com/airbnb/visx.git"
},
"keywords": [
"visx",
"react",
"d3",
"visualizations",
"charts"
],
"author": "@hshoff",
"license": "MIT",
"bugs": {
"url": "https://github.com/airbnb/visx/issues"
},
"homepage": "https://github.com/airbnb/visx#readme",
"peerDependencies": {
"@types/react": "^18.0.0 || ^19.0.0",
"react": "^18.0.0 || ^19.0.0"
},
"dependencies": {
"@visx/drag": "workspace:",
"@visx/group": "workspace:",
"@visx/text": "workspace:*",
"classnames": "^2.3.1",
"react-use-measure": "^2.0.4"
},
"devDependencies": {
"@juggle/resize-observer": "^3.3.1",
"@types/react": "^19.0.0"
},
"publishConfig": {
"access": "public"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
}
File: packages/visx-annotation/tsconfig.json
{
"compilerOptions": {
"declarationDir": "lib",
"outDir": "lib",
"rootDir": "src"
},
"exclude": [
"lib",
"test"
],
"extends": "../../tsconfig.options.json",
"include": [
"src//*",
"types//",
"../../types/**/"
],
"references": [
{
"path": "../visx-drag"
},
{
"path": "../visx-group"
},
{
"path": "../visx-text"
}
]
}
File: packages/visx-annotation/test/tsconfig.json
{
"compilerOptions": {
"composite": false,
"emitDeclarationOnly": false,
"noEmit": true,
"rootDir": ".",
"types": ["vitest/globals"]
},
"extends": "../../../tsconfig.options.json",
"include": ["/*", "../types//", "../../../types/**/"],
"references": [
{
"path": ".."
}
]
}
File: packages/visx-axis/Readme.md
@visx/axis
An axis component consists of a line with ticks, tick labels, and an axis label that helps viewers
interpret your graph.
You can use one of the 4 pre-made axes, or you can create your own based on the <Axis /> element.
Note that the @visx/react-spring package exports an AnimatedAxis variant with animated ticks.
Installation
npm install --save @visx/axisFile: packages/visx-axis/package.json
{
"name": "@visx/axis",
"version": "4.0.0",
"description": "visx axis",
"sideEffects": false,
"main": "lib/index.js",
"module": "esm/index.js",
"types": "lib/index.d.ts",
"exports": {
".": {
"types": "./lib/index.d.ts",
"import": "./esm/index.js",
"require": "./lib/index.js"
},
"./react": {
"types": "./lib/react/index.d.ts",
"import": "./esm/react/index.js",
"require": "./lib/react/index.js"
}
},
"files": [
"lib",
"esm"
],
"repository": {
"type": "git",
"url": "git+https://github.com/airbnb/visx.git"
},
"keywords": [
"visx",
"react",
"d3",
"visualizations",
"charts"
],
"author": "@hshoff",
"license": "MIT",
"bugs": {
"url": "https://github.com/airbnb/visx/issues"
},
"homepage": "https://github.com/airbnb/visx#readme",
"dependencies": {
"@visx/group": "workspace:",
"@visx/point": "workspace:",
"@visx/scale": "workspace:",
"@visx/shape": "workspace:",
"@visx/text": "workspace:*",
"classnames": "^2.3.1"
},
"peerDependencies": {
"@types/react": "^18.0.0 || ^19.0.0",
"react": "^18.0.0 || ^19.0.0"
},
"publishConfig": {
"access": "public"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
},
"devDependencies": {
"@types/react": "^19.0.0"
}
}
File: packages/visx-axis/tsconfig.json
{
"compilerOptions": {
"declarationDir": "lib",
"outDir": "lib",
"rootDir": "src"
},
"exclude": [
"lib",
"test"
],
"extends": "../../tsconfig.options.json",
"include": [
"src//*",
"types//",
"../../types/**/"
],
"references": [
{
"path": "../visx-group"
},
{
"path": "../visx-point"
},
{
"path": "../visx-scale"
},
{
"path": "../visx-shape"
},
{
"path": "../visx-text"
}
]
}
File: packages/visx-axis/test/tsconfig.json
{
"compilerOptions": {
"composite": false,
"emitDeclarationOnly": false,
"noEmit": true,
"rootDir": ".",
"types": ["vitest/globals"]
},
"extends": "../../../tsconfig.options.json",
"include": ["/*", "../types//", "../../../types/**/"],
"references": [
{
"path": ".."
}
]
}
File: packages/visx-bounds/Readme.md
@visx/bounds
npm install --save @visx/bounds`withBoundingRects` HOC
It's often useful to determine whether elements (e.g., tooltips) overflow the bounds of their parent
container and adjust positioning accordingly. The withBoundingRects higher-order component is
meant to simplify this computation by passing in a component's bounding rect as well as its
parent's bounding rect.
Example usage
Example usage with a <Tooltip /> component
import React from 'react';
import { withBoundingRects, WithBoundingRectsProps } from '@visx/bounds';
type TooltipProps = Omit<WithBoundingRectsProps, 'nodeRef'> & {
left: number;
top: number;
nodeRef?: React.Ref<HTMLDivElement>;
children?: React.ReactNode;
};
function Tooltip({
left: initialLeft,
top: initialTop,
rect,
parentRect,
nodeRef,
children,
}: TooltipProps) {
let left = initialLeft;
let top = initialTop;
if (rect && parentRect) {
left = rect.right > parentRect.right ? left - rect.width : left;
top = rect.bottom > parentRect.bottom ? top - rect.height : top;
}
return (
<div ref={nodeRef} style={{ top, left, ...myTheme }}>
{children}
</div>
);
}
export default withBoundingRects(Tooltip);File: packages/visx-bounds/package.json
{
"name": "@visx/bounds",
"version": "4.0.0",
"description": "Utilities to make your life with bounding boxes better",
"sideEffects": false,
"main": "lib/index.js",
"module": "esm/index.js",
"types": "lib/index.d.ts",
"exports": {
".": {
"types": "./lib/index.d.ts",
"import": "./esm/index.js",
"require": "./lib/index.js"
}
},
"files": [
"lib",
"esm"
],
"repository": {
"type": "git",
"url": "git+https://github.com/airbnb/visx.git"
},
"keywords": [
"visx",
"react",
"visualizations",
"charts"
],
"author": "Chris Williams @williaster",
"license": "MIT",
"bugs": {
"url": "https://github.com/airbnb/visx/issues"
},
"homepage": "https://github.com/airbnb/visx#readme",
"publishConfig": {
"access": "public"
},
"peerDependencies": {
"@types/react": "^18.0.0 || ^19.0.0",
"@types/react-dom": "^18.0.0 || ^19.0.0",
"react": "^18.0.0 || ^19.0.0",
"react-dom": "^18.0.0 || ^19.0.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
}
File: packages/visx-bounds/tsconfig.json
{
"compilerOptions": {
"declarationDir": "lib",
"outDir": "lib",
"rootDir": "src"
},
"exclude": [
"lib",
"test"
],
"extends": "../../tsconfig.options.json",
"include": [
"src//*",
"types//",
"../../types/**/"
],
"references": []
}
File: packages/visx-bounds/test/tsconfig.json
{
"compilerOptions": {
"composite": false,
"emitDeclarationOnly": false,
"noEmit": true,
"rootDir": ".",
"types": ["vitest/globals"]
},
"extends": "../../../tsconfig.options.json",
"include": ["/*", "../types//", "../../../types/**/"],
"references": [
{
"path": ".."
}
]
}
File: packages/visx-brush/Readme.md
@visx/brush
A brush allows you to select a sub-region of your chart or axis.
Installation
npm install --save @visx/brushFile: packages/visx-brush/package.json
{
"name": "@visx/brush",
"version": "4.0.0",
"description": "visx brush",
"sideEffects": false,
"main": "lib/index.js",
"module": "esm/index.js",
"files": [
"lib",
"esm"
],
"repository": {
"type": "git",
"url": "git+https://github.com/airbnb/visx.git"
},
"keywords": [
"visx",
"d3",
"react",
"visualizations",
"charts"
],
"author": "@hshoff",
"license": "MIT",
"bugs": {
"url": "https://github.com/airbnb/visx/issues"
},
"homepage": "https://github.com/airbnb/visx#readme",
"publishConfig": {
"access": "public"
},
"peerDependencies": {
"@types/react": "^18.0.0 || ^19.0.0",
"react": "^18.0.0 || ^19.0.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
},
"dependencies": {
"@visx/drag": "workspace:",
"@visx/event": "workspace:",
"@visx/group": "workspace:",
"@visx/scale": "workspace:",
"@visx/shape": "workspace:*",
"classnames": "^2.3.1"
},
"exports": {
".": {
"types": "./lib/index.d.ts",
"import": "./esm/index.js",
"require": "./lib/index.js"
}
},
"devDependencies": {
"@types/react": "^19.0.0"
}
}
File: packages/visx-brush/tsconfig.json
{
"compilerOptions": {
"declarationDir": "lib",
"outDir": "lib",
"rootDir": "src"
},
"exclude": [
"lib",
"test"
],
"extends": "../../tsconfig.options.json",
"include": [
"src//*",
"types//",
"../../types/**/"
],
"references": [
{
"path": "../visx-drag"
},
{
"path": "../visx-event"
},
{
"path": "../visx-group"
},
{
"path": "../visx-scale"
},
{
"path": "../visx-shape"
}
]
}
File: packages/visx-brush/test/tsconfig.json
{
"compilerOptions": {
"composite": false,
"emitDeclarationOnly": false,
"noEmit": true,
"rootDir": ".",
"types": ["vitest/globals"]
},
"extends": "../../../tsconfig.options.json",
"include": ["/*", "../types//", "../../../types/**/"],
"references": [
{
"path": ".."
}
]
}
File: packages/visx-chart/Readme.md
@visx/chart
Chart-level React hooks and helpers for building primitive visx charts without adopting a chart
framework. The package starts with shared layout and domain helpers that registry-style charts can
use before composing @visx/axis, @visx/scale, @visx/shape, and other low-level primitives.
Installation
npm install --save @visx/chartMotivation
visx charts are usually assembled from several packages: one package for scales, one for axes, one
for marks, one for interaction, and application code for the SVG frame around them. That composition
is the point, but every primitive chart still tends to rebuild the same chart-level setup:
- outer SVG dimensions
- margin defaults
- inner drawable width and height
xMaxandyMaxaliases used throughout visx examples- common numeric domains for primitive chart scales
- responsive width fallbacks while parent measurement initializes
- stable layout objects for downstream hooks and components
Those details are small, but they become repetitive in examples, dashboards, and registry items.@visx/chart gives primitive charts one shared place for that chart-level setup while leaving scale
construction, rendering, interaction, animation, and state ownership in user code.
Primitive-first design
The chart package is a convenience layer, not a chart framework.
- Hooks return ordinary values that can be passed to any visx primitive.
- The package does not render SVG elements or own a chart scene graph.
- Data accessors, scales, axes, marks, events, and animation remain explicit.
- Layout defaults are normalized, but callers can keep their own sizing system.
- You can use the chart hooks with one visx package, many visx packages, or custom SVG.
This keeps registry examples compact without hiding the pieces that make visx flexible. If a chart
needs a custom margin model, responsive container, canvas renderer, or no shared layout helper at
all, the primitive API still supports that.
Basic usage
Use useChartDimensions to normalize an outer chart size and margin into the inner drawing area.
import { Group } from '@visx/group';
import { useChartDimensions } from '@visx/chart';
const margin = { top: 16, right: 16, bottom: 32, left: 40 };
export function ChartFrame({ width, height, children }) {
const dimensions = useChartDimensions({ width, height, margin });
return (
<svg width={dimensions.width} height={dimensions.height}>
<Group left={dimensions.margin.left} top={dimensions.margin.top}>
{children(dimensions)}
</Group>
</svg>
);
}The hook fills missing margin sides with 0, treats non-finite dimensions as 0, and clamps the
inner drawing area to 0 so marks never receive negative layout space.
Numeric domains
Use the domain helpers when a primitive chart needs the usual safe defaults for empty, invalid, or
single-value data.
import { getPositiveDomain, getZeroBaselineDomain } from '@visx/chart';
const yDomain = getZeroBaselineDomain(data.map((datum) => datum.value));
const stackedYDomain = getPositiveDomain(
data.map((datum) => datum.desktop + datum.mobile + datum.tablet),
);getZeroBaselineDomain includes zero and expands equal domains. getPositiveDomain returns a
positive [0, max] domain with an empty fallback of [0, 1]. getPaddedDomain is available for
plots such as scatter charts where the domain should wrap finite values with proportional padding.
Axis ticks
Use the tick helpers when a chart axis may become too dense in responsive layouts.getVisibleTickValues thins explicit category tick values while preserving the first and last tick
by default, and getAxisTickCount computes a conservative numeric tick count from the available
axis length.
import { getAxisTickCount, getVisibleTickValues } from '@visx/chart';
const xTickValues = getVisibleTickValues(months, {
axisLength: dimensions.innerWidth,
minTickSpacing: 48,
});
const yNumTicks = getAxisTickCount({
axisLength: dimensions.innerHeight,
maxTicks: 5,
minTickSpacing: 48,
});The helpers only choose visible axis labels. They do not remove data points, bars, bins, or table
fallback rows.
Responsive width fallback
Use getResponsiveWidth when a responsive container may report 0, NaN, or another
non-renderable width while layout measurement initializes.
import { getResponsiveWidth } from '@visx/chart';
const chartWidth = getResponsiveWidth(measuredWidth, 640);The helper returns the measured width only when it is finite and greater than 0; otherwise it
returns the fallback width.
Chart config
Use ChartConfig when labels, colors, icons, and theme-specific tokens should live outside the
chart data. This mirrors the way registry charts are usually copied into app code: the data can come
from an API while chart presentation stays colocated with the component.
import { getChartConfigColor, getChartConfigLabel, type ChartConfig } from '@visx/chart';
const chartConfig = {
bookings: {
label: 'Bookings',
color: 'var(--chart-1)',
},
revenue: {
label: 'Revenue',
theme: {
light: 'oklch(0.646 0.222 41.116)',
dark: 'oklch(0.488 0.243 264.376)',
},
},
} satisfies ChartConfig;
const label = getChartConfigLabel(chartConfig, 'bookings');
const color = getChartConfigColor(chartConfig, 'bookings', 'currentColor');getChartCssVariables can turn a config into --color-* CSS variables for chart shells that want
the same token style as copied registry components.
Working with scales
xMax and yMax are aliases for innerWidth and innerHeight, matching the naming used in many
visx examples.
import { useChartDimensions } from '@visx/chart';
import { useScale } from '@visx/scale/react';
export function useRevenueScales({ data, width, height }) {
const dimensions = useChartDimensions({
width,
height,
margin: { top: 16, right: 16, bottom: 32, left: 48 },
});
const maxRevenue = Math.max(0, ...data.map((datum) => datum.revenue));
const xScale = useScale({
type: 'band',
domain: data.map((datum) => datum.month),
range: [0, dimensions.xMax],
padding: 0.2,
});
const yScale = useScale({
type: 'linear',
domain: [0, maxRevenue],
range: [dimensions.yMax, 0],
nice: true,
});
return { dimensions, xScale, yScale };
}Recipes
Bar chart shell
import { AxisBottom, AxisLeft } from '@visx/axis';
import { Group } from '@visx/group';
import { Bar } from '@visx/shape';
import { useChartDimensions } from '@visx/chart';
import { useScale } from '@visx/scale/react';
const margin = { top: 16, right: 16, bottom: 32, left: 48 };
export function RevenueBars({ data, width, height }) {
const dimensions = useChartDimensions({ width, height, margin });
const maxRevenue = Math.max(0, ...data.map((datum) => datum.revenue));
const xScale = useScale({
type: 'band',
domain: data.map((datum) => datum.month),
range: [0, dimensions.xMax],
padding: 0.2,
});
const yScale = useScale({
type: 'linear',
domain: [0, maxRevenue],
range: [dimensions.yMax, 0],
nice: true,
});
return (
<svg width={dimensions.width} height={dimensions.height}>
<Group left={dimensions.margin.left} top={dimensions.margin.top}>
{data.map((datum) => {
const barX = xScale(datum.month) ?? 0;
const barY = yScale(datum.revenue) ?? 0;
return (
<Bar
key={datum.month}
x={barX}
y={barY}
width={xScale.bandwidth()}
height={dimensions.yMax - barY}
fill="currentColor"
/>
);
})}
<AxisBottom top={dimensions.yMax} scale={xScale} />
<AxisLeft scale={yScale} />
</Group>
</svg>
);
}Responsive dimensions
useChartDimensions does not measure the DOM. Pair it with your app's layout system or with@visx/responsive when a chart should fill available space.
import { getResponsiveWidth } from '@visx/chart';
import { ParentSize } from '@visx/responsive';
export function ResponsiveRevenueBars({ data }) {
return (
<ParentSize>
{({ width }) => (
<RevenueBars data={data} width={getResponsiveWidth(width, 640)} height={320} />
)}
</ParentSize>
);
}File: packages/visx-chart/package.json
{
"name": "@visx/chart",
"version": "4.0.0",
"description": "visx chart-level hooks",
"sideEffects": false,
"main": "lib/index.js",
"module": "esm/index.js",
"types": "lib/index.d.ts",
"exports": {
".": {
"types": "./lib/index.d.ts",
"import": "./esm/index.js",
"require": "./lib/index.js"
}
},
"files": [
"lib",
"esm"
],
"repository": {
"type": "git",
"url": "git+https://github.com/airbnb/visx.git"
},
"keywords": [
"visx",
"react",
"visualizations",
"charts",
"hooks"
],
"author": "@hshoff",
"license": "MIT",
"bugs": {
"url": "https://github.com/airbnb/visx/issues"
},
"homepage": "https://github.com/airbnb/visx#readme",
"dependencies": {
"@visx/kernel": "workspace:*"
},
"peerDependencies": {
"@types/react": "^18.0.0 || ^19.0.0",
"react": "^18.0.0 || ^19.0.0"
},
"publishConfig": {
"access": "public"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
},
"devDependencies": {
"@types/react": "^19.0.0"
}
}
File: packages/visx-chart/tsconfig.json
{
"compilerOptions": {
"declarationDir": "lib",
"outDir": "lib",
"rootDir": "src"
},
"exclude": [
"lib",
"test"
],
"extends": "../../tsconfig.options.json",
"include": [
"src//*",
"types//",
"../../types/**/"
],
"references": [
{
"path": "../visx-kernel"
}
]
}
File: packages/visx-chord/Readme.md
@visx/chord
Chord diagrams show directed relationships among a group of entities in a radial layout.
Installation
npm install --save @visx/chordFile: packages/visx-chord/package.json
{
"name": "@visx/chord",
"version": "4.0.0",
"description": "visx group",
"sideEffects": false,
"main": "lib/index.js",
"module": "esm/index.js",
"types": "lib/index.d.ts",
"exports": {
".": {
"types": "./lib/index.d.ts",
"import": "./esm/index.js",
"require": "./lib/index.js"
}
},
"files": [
"lib",
"esm"
],
"repository": {
"type": "git",
"url": "git+https://github.com/airbnb/visx.git"
},
"keywords": [
"visx",
"react",
"d3",
"visualizations",
"charts",
"svg"
],
"author": "@hshoff",
"license": "MIT",
"bugs": {
"url": "https://github.com/airbnb/visx/issues"
},
"homepage": "https://github.com/airbnb/visx#readme",
"peerDependencies": {
"@types/react": "^18.0.0 || ^19.0.0",
"react": "^18.0.0 || ^19.0.0"
},
"dependencies": {
"@types/d3-chord": "^1.0.9",
"classnames": "^2.3.1",
"d3-chord": "^1.0.4"
},
"publishConfig": {
"access": "public"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
}
File: packages/visx-chord/tsconfig.json
{
"compilerOptions": {
"declarationDir": "lib",
"outDir": "lib",
"rootDir": "src"
},
"exclude": [
"lib",
"test"
],
"extends": "../../tsconfig.options.json",
"include": [
"src//*",
"types//",
"../../types/**/"
],
"references": []
}
File: packages/visx-chord/test/tsconfig.json
{
"compilerOptions": {
"composite": false,
"emitDeclarationOnly": false,
"noEmit": true,
"rootDir": ".",
"types": ["vitest/globals"]
},
"extends": "../../../tsconfig.options.json",
"include": ["/*", "../types//", "../../../types/**/"],
"references": [
{
"path": ".."
}
]
}
File: packages/visx-clip-path/Readme.md
@visx/clip-path
React utilities for defining <clipPath> SVG elements, with or without data, to be clip masks for
other SVG elements by using their clip-path property.
Installation
npm install --save @visx/clip-pathFile: packages/visx-clip-path/package.json
{
"name": "@visx/clip-path",
"version": "4.0.0",
"description": "visx clip-path",
"sideEffects": false,
"main": "lib/index.js",
"module": "esm/index.js",
"types": "lib/index.d.ts",
"exports": {
".": {
"types": "./lib/index.d.ts",
"import": "./esm/index.js",
"require": "./lib/index.js"
}
},
"files": [
"lib",
"esm"
],
"repository": {
"type": "git",
"url": "git+https://github.com/airbnb/visx.git"
},
"keywords": [
"visx",
"react",
"d3",
"visualizations",
"charts",
"svg"
],
"author": "Chris Williams @williaster",
"license": "MIT",
"bugs": {
"url": "https://github.com/airbnb/visx/issues"
},
"homepage": "https://github.com/airbnb/visx#readme",
"peerDependencies": {
"@types/react": "^18.0.0 || ^19.0.0",
"react": "^18.0.0 || ^19.0.0"
},
"publishConfig": {
"access": "public"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
}
File: packages/visx-clip-path/tsconfig.json
{
"compilerOptions": {
"declarationDir": "lib",
"outDir": "lib",
"rootDir": "src"
},
"exclude": [
"lib",
"test"
],
"extends": "../../tsconfig.options.json",
"include": [
"src//*",
"types//",
"../../types/**/"
],
"references": []
}
File: packages/visx-clip-path/test/tsconfig.json
{
"compilerOptions": {
"composite": false,
"emitDeclarationOnly": false,
"noEmit": true,
"rootDir": ".",
"types": ["vitest/globals"]
},
"extends": "../../../tsconfig.options.json",
"include": ["/*", "../types//", "../../../types/**/"],
"references": [
{
"path": ".."
}
]
}
File: packages/visx-curve/Readme.md
@visx/curve
Installation
npm install --save @visx/curveOverview
The @visx/curve package is a wrapper of the d3-shape curve
functions. A curve is a function that can be passed into other visx objects that draw lines or
paths, such as a LinePath, to change the way the line between points is drawn. Click on the
example below for an interactive way to explore curve aesthetics.
Any function with the prefix curve in d3 can be used through visx like so:
import { curveCatmullRomOpen } from '@visx/curve';
let line = (<Shape.LinePath curve={curveCatmullRomOpen} />)
// or if you want namespace all Curves under the `Curve`
import * as Curve from `@visx/curve`;
let line = (<Shape.LinePath curve={Curve.curveCatmullRomOpen} />)Functions
| visx | d3 |
|---|---|
| curveBasis | curveBasis |
| curveBasisClose | curveBasisClosed |
| curveBasisOpen | curveBasisOpen |
| curveStep | curveStep |
| curveStepAfter | curveStepAfter |
| curveStepBefore | curveStepbefore |
| curveBundle | curveBundle |
| curveLinear | curveLinear |
| curveLinearClosed | curveLinearClosed |
| curveMonotoneX | curveMonotoneX |
| curveMonotoneY | curveMonotoneY |
| curveCardinal | curveCardinal |
| curveCardinalClosed | curveCardinalClosed |
| curveCardinalOpen | curveCardinalOpen |
| curveCatmullRom | curveCatmullRom |
| curveCatmullRomClosed | curveCatmullRomClosed |
| curveCatmullRomOpen | curveCatmullRomOpen |
| curveNatural | curveNatural |
File: packages/visx-curve/package.json
{
"name": "@visx/curve",
"version": "4.0.0",
"description": "visx curve",
"sideEffects": false,
"main": "lib/index.js",
"module": "esm/index.js",
"types": "lib/index.d.ts",
"exports": {
".": {
"types": "./lib/index.d.ts",
"import": "./esm/index.js",
"require": "./lib/index.js"
}
},
"repository": "https://github.com/airbnb/visx",
"files": [
"lib",
"esm"
],
"keywords": [
"visx",
"react",
"d3",
"visualization",
"chart"
],
"author": "@hshoff",
"license": "MIT",
"dependencies": {
"@visx/vendor": "workspace:*"
},
"publishConfig": {
"access": "public"
}
}
File: packages/visx-curve/tsconfig.json
{
"compilerOptions": {
"declarationDir": "lib",
"outDir": "lib",
"rootDir": "src"
},
"exclude": [
"lib",
"test"
],
"extends": "../../tsconfig.options.json",
"include": [
"src//*",
"types//",
"../../types/**/"
],
"references": [
{
"path": "../visx-vendor"
}
]
}
File: packages/visx-curve/test/tsconfig.json
{
"compilerOptions": {
"composite": false,
"emitDeclarationOnly": false,
"noEmit": true,
"rootDir": ".",
"types": ["vitest/globals"]
},
"extends": "../../../tsconfig.options.json",
"include": ["/*", "../types//", "../../../types/**/"],
"references": [
{
"path": ".."
}
]
}
File: packages/visx-delaunay/Readme.md
@visx/delaunay
Overview
A Voronoi diagram partitions a two-dimensional plane into regions based on a set of input points.
Each unique input point maps to a corresponding region, where each region represents all points
that are closer to the input point than to any other input point.
Not only are Voronoi diagrams 😍, but they can be used to
improve the interactive experience of a visualization.
This is most often accomplished by overlaying an invisible voronoi grid on top of the visualization
to increase the target area of interaction sites such as points on a scatter plot.
The @visx/delaunay package provides a wrapper around the existing
d3-delaunay package with some react-specific utilities.
Installation
npm install --save @visx/delaunayUsage
The @visx/delaunay package exports a wrapped version of the d3 voronoi and delaunay layouts for flexible usage,
as well as a `` component for rendering Voronoi and Delaunay regions.
import { voronoi, Polygon } from '@visx/delaunay';
const points = Array(n).fill(null).map(() => ({
x: Math.random() * innerWidth,
y: Math.random() * innerHeight,
}));
// width + height set an extent on the voronoi
// x + y set relevant accessors depending on the shape of your data
const voronoiDiagram = voronoi({
data: points,
x: d => d.x,
y: d => d.y,
width,
height,
});
const polygons = Array.from(voronoiDiagram.cellPolygons());
return (
<svg>
<Group>
{polygons.map((polygon) => (
<Polygon key={...} polygon={polygon} />
))}
{points.map(({ x, y }) => (
<circle key={...} cx={x} cy={y} />
)}
</Group>
</svg>
)Additional information about the voronoi diagram API can be found in the
d3-delaunay documentation.
File: packages/visx-delaunay/package.json
{
"name": "@visx/delaunay",
"version": "4.0.0",
"description": "visx delaunay",
"sideEffects": false,
"main": "lib/index.js",
"module": "esm/index.js",
"types": "lib/index.d.ts",
"exports": {
".": {
"types": "./lib/index.d.ts",
"import": "./esm/index.js",
"require": "./lib/index.js"
}
},
"files": [
"lib",
"esm"
],
"repository": {
"type": "git",
"url": "git+https://github.com/airbnb/visx.git"
},
"keywords": [
"visx",
"react",
"d3",
"visualizations",
"charts"
],
"author": "@SheaJanke",
"license": "MIT",
"bugs": {
"url": "https://github.com/airbnb/visx/issues"
},
"homepage": "https://github.com/airbnb/visx#readme",
"publishConfig": {
"access": "public"
},
"dependencies": {
"@visx/vendor": "workspace:*",
"classnames": "^2.3.1"
},
"peerDependencies": {
"@types/react": "^18.0.0 || ^19.0.0",
"react": "^18.0.0 || ^19.0.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
}
File: packages/visx-delaunay/tsconfig.json
{
"compilerOptions": {
"declarationDir": "lib",
"outDir": "lib",
"rootDir": "src"
},
"exclude": [
"lib",
"test"
],
"extends": "../../tsconfig.options.json",
"include": [
"src//*",
"types//",
"../../types/**/"
],
"references": [
{
"path": "../visx-vendor"
}
]
}
File: packages/visx-delaunay/test/tsconfig.json
{
"compilerOptions": {
"composite": false,
"emitDeclarationOnly": false,
"noEmit": true,
"rootDir": ".",
"types": ["vitest/globals"]
},
"extends": "../../../tsconfig.options.json",
"include": ["/*", "../types//", "../../../types/**/"],
"references": [
{
"path": ".."
}
]
}
File: packages/visx-demo/Readme.md
@visx/demo
https://airbnb.io/visx/gallery
File: packages/visx-demo/package.json
{
"name": "@visx/demo",
"version": "4.0.0",
"description": "visx demo",
"repository": "https://github.com/airbnb/visx",
"scripts": {
"build": "next build",
"deploy": "rm -rf out && yarn build && cd out && touch .nojekyll && git init && git add . && git commit -m "Deploy commit" && git remote add origin [email protected]:airbnb/visx.git && git push -f origin master:gh-pages",
"dev": "next",
"preview": "yarn build && cd ./out && npx serve",
"start": "next start"
},
"keywords": [
"visx",
"demo",
"examples"
],
"contributors": [
{
"name": "Harrison Shoff",
"url": "https://github.com/hshoff"
},
{
"name": "Chris Williams",
"url": "https://github.com/williaster"
}
],
"license": "MIT",
"dependencies": {
"@react-spring/web": "^10.0.3",
"@types/d3-scale-chromatic": "^3.1.0",
"@types/nprogress": "^0.2.0",
"@types/prismjs": "^1.16.0",
"@visx/annotation": "workspace:",
"@visx/axis": "workspace:",
"@visx/bounds": "workspace:",
"@visx/brush": "workspace:",
"@visx/chord": "workspace:",
"@visx/clip-path": "workspace:",
"@visx/curve": "workspace:",
"@visx/delaunay": "workspace:",
"@visx/drag": "workspace:",
"@visx/event": "workspace:",
"@visx/geo": "workspace:",
"@visx/glyph": "workspace:",
"@visx/gradient": "workspace:",
"@visx/grid": "workspace:",
"@visx/group": "workspace:",
"@visx/heatmap": "workspace:",
"@visx/hierarchy": "workspace:",
"@visx/legend": "workspace:",
"@visx/marker": "workspace:",
"@visx/mock-data": "workspace:",
"@visx/network": "workspace:",
"@visx/pattern": "workspace:",
"@visx/point": "workspace:",
"@visx/react-spring": "workspace:",
"@visx/responsive": "workspace:",
"@visx/sankey": "workspace:",
"@visx/scale": "workspace:",
"@visx/shape": "workspace:",
"@visx/stats": "workspace:",
"@visx/text": "workspace:",
"@visx/theme": "workspace:",
"@visx/threshold": "workspace:",
"@visx/tooltip": "workspace:",
"@visx/vendor": "workspace:",
"@visx/visx": "workspace:",
"@visx/voronoi": "workspace:",
"@visx/wordcloud": "workspace:",
"@visx/xychart": "workspace:",
"@visx/zoom": "workspace:*",
"babel-loader": "^8.2.2",
"classnames": "^2.3.1",
"d3-collection": "^1.0.7",
"d3-hierarchy": "^3.1.2",
"d3-scale-chromatic": "^3.1.0",
"d3-shape": "^3.2.0",
"next": "~15.5.18",
"nprogress": "^0.2.0",
"prismjs": "^1.19.0",
"raw-loader": "^4.0.0",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"react-github-button": "^0.1.10",
"react-markdown": "^9.0.1",
"rehype-raw": "^7.0.0",
"topojson-client": "^3.0.0"
},
"devDependencies": {
"@babel/core": "^7.26.0",
"@types/react": "^19.0.0",
"@types/react-dom": "^19.0.0"
},
"publishConfig": {
"access": "public"
}
}
File: packages/visx-demo/tsconfig.json
{
"compilerOptions": {
"allowJs": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"isolatedModules": true,
"jsx": "preserve",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"module": "esnext",
"moduleResolution": "node",
"composite": true,
"outDir": "lib",
"resolveJsonModule": true,
"rootDir": "src",
"skipLibCheck": true,
"strict": false,
"target": "es5",
"noEmit": true,
"incremental": true
},
"exclude": [
"lib",
"test",
"src/sandboxes//package.json"
],
"include": [
"src//.{ts,tsx}",
"../../types/**/.{ts,tsx}"
],
"references": [
{
"path": "../visx-annotation"
},
{
"path": "../visx-axis"
},
{
"path": "../visx-bounds"
},
{
"path": "../visx-brush"
},
{
"path": "../visx-chord"
},
{
"path": "../visx-clip-path"
},
{
"path": "../visx-curve"
},
{
"path": "../visx-delaunay"
},
{
"path": "../visx-drag"
},
{
"path": "../visx-event"
},
{
"path": "../visx-geo"
},
{
"path": "../visx-glyph"
},
{
"path": "../visx-gradient"
},
{
"path": "../visx-grid"
},
{
"path": "../visx-group"
},
{
"path": "../visx-heatmap"
},
{
"path": "../visx-hierarchy"
},
{
"path": "../visx-legend"
},
{
"path": "../visx-marker"
},
{
"path": "../visx-mock-data"
},
{
"path": "../visx-network"
},
{
"path": "../visx-pattern"
},
{
"path": "../visx-point"
},
{
"path": "../visx-react-spring"
},
{
"path": "../visx-responsive"
},
{
"path": "../visx-sankey"
},
{
"path": "../visx-scale"
},
{
"path": "../visx-shape"
},
{
"path": "../visx-stats"
},
{
"path": "../visx-text"
},
{
"path": "../visx-theme"
},
{
"path": "../visx-threshold"
},
{
"path": "../visx-tooltip"
},
{
"path": "../visx-vendor"
},
{
"path": "../visx-visx"
},
{
"path": "../visx-voronoi"
},
{
"path": "../visx-wordcloud"
},
{
"path": "../visx-xychart"
},
{
"path": "../visx-zoom"
}
]
}
File: packages/visx-demo/vercel.json
{
"version": 2,
"cleanUrls": true
}
File: packages/visx-demo/src/sandboxes/README.md
Examples
This directory contains examples of visx usage.
Each folder is a complete standalone project, and is imported using the Code Sandbox
import from GitHub feature.
File: packages/visx-demo/src/sandboxes/template/package.json
{
"name": "@visx/demo-example",
"description": "Standalone visx demo.",
"main": "index.tsx",
"private": true,
"dependencies": {
"@babel/runtime": "^7.8.4",
"@types/react": "^18",
"@types/react-dom": "^18",
"@visx/responsive": "latest",
"react": "^18",
"react-dom": "^18",
"react-scripts-ts": "3.1.0",
"typescript": "^3"
},
"keywords": [
"visualization",
"d3",
"react",
"visx"
]
}
File: packages/visx-demo/src/sandboxes/visx-annotation/package.json
{
"name": "@visx/demo-annotation",
"description": "Standalone visx annotation demo.",
"main": "index.tsx",
"private": true,
"dependencies": {
"@babel/runtime": "^7.8.4",
"@types/react": "^18",
"@types/react-dom": "^18",
"@visx/annotation": "latest",
"@visx/mock-data": "latest",
"@visx/responsive": "latest",
"@visx/scale": "latest",
"@visx/shape": "latest",
"@visx/vendor": "latest",
"react": "^18",
"react-dom": "^18",
"react-scripts-ts": "3.1.0",
"typescript": "^3"
},
"keywords": [
"visualization",
"d3",
"react",
"visx",
"annotation"
]
}
File: packages/visx-demo/src/sandboxes/visx-area/package.json
{
"name": "@visx/demo-area",
"description": "Standalone visx area demo.",
"main": "index.tsx",
"private": true,
"dependencies": {
"@babel/runtime": "^7.8.4",
"@types/react": "^18",
"@types/react-dom": "^18",
"@visx/curve": "latest",
"@visx/event": "latest",
"@visx/gradient": "latest",
"@visx/grid": "latest",
"@visx/mock-data": "latest",
"@visx/responsive": "latest",
"@visx/scale": "latest",
"@visx/shape": "latest",
"@visx/tooltip": "latest",
"@visx/vendor": "latest",
"react": "^18",
"react-dom": "^18",
"react-scripts-ts": "3.1.0",
"typescript": "^3"
},
"keywords": [
"visualization",
"d3",
"react",
"visx",
"area"
]
}
File: packages/visx-demo/src/sandboxes/visx-axis/package.json
{
"name": "@visx/demo-axis",
"description": "Standalone axis demo.",
"main": "index.tsx",
"private": true,
"dependencies": {
"@babel/runtime": "^7.8.4",
"@types/react": "^18",
"@types/react-dom": "^18",
"@visx/axis": "latest",
"@visx/curve": "latest",
"@visx/gradient": "latest",
"@visx/grid": "latest",
"@visx/group": "latest",
"@visx/mock-data": "latest",
"@visx/react-spring": "latest",
"@visx/responsive": "latest",
"@visx/shape": "latest",
"@visx/scale": "latest",
"@visx/vendor": "latest",
"react": "^18",
"react-dom": "^18",
"react-scripts-ts": "3.1.0",
"@react-spring/web": "^10.0.3",
"typescript": "^3"
},
"keywords": [
"axis",
"scales",
"visualization",
"d3",
"react",
"visx"
]
}
File: packages/visx-demo/src/sandboxes/visx-bargroup/package.json
{
"name": "@visx/demo-bargroup",
"description": "Standalone visx grouped bar demo.",
"main": "index.tsx",
"private": true,
"dependencies": {
"@babel/runtime": "^7.8.4",
"@types/react": "^18",
"@types/react-dom": "^18",
"@visx/axis": "latest",
"@visx/group": "latest",
"@visx/mock-data": "latest",
"@visx/responsive": "latest",
"@visx/scale": "latest",
"@visx/shape": "latest",
"@visx/vendor": "latest",
"react": "^18",
"react-dom": "^18",
"react-scripts-ts": "3.1.0",
"typescript": "^3"
},
"keywords": [
"visualization",
"d3",
"react",
"visx",
"bargroup"
]
}
File: packages/visx-demo/src/sandboxes/visx-bargroup-horizontal/package.json
{
"name": "@visx/demo-bargroup-horizontal",
"description": "Standalone visx horizontal grouped bar demo.",
"main": "index.tsx",
"private": true,
"dependencies": {
"@babel/runtime": "^7.8.4",
"@types/react": "^18",
"@types/react-dom": "^18",
"@visx/axis": "latest",
"@visx/group": "latest",
"@visx/mock-data": "latest",
"@visx/responsive": "latest",
"@visx/scale": "latest",
"@visx/shape": "latest",
"@visx/vendor": "latest",
"react": "^18",
"react-dom": "^18",
"react-scripts-ts": "3.1.0",
"typescript": "^3"
},
"keywords": [
"visualization",
"d3",
"react",
"visx",
"bargroup"
]
}
File: packages/visx-demo/src/sandboxes/visx-bars/package.json
{
"name": "@visx/demo-bars",
"description": "Standalone visx bars demo.",
"main": "index.tsx",
"private": true,
"dependencies": {
"@babel/runtime": "^7.8.4",
"@types/react": "^18",
"@types/react-dom": "^18",
"@visx/gradient": "latest",
"@visx/group": "latest",
"@visx/mock-data": "latest",
"@visx/responsive": "latest",
"@visx/scale": "latest",
"@visx/shape": "latest",
"react": "^18",
"react-dom": "^18",
"react-scripts-ts": "3.1.0",
"typescript": "^3"
},
"keywords": [
"visualization",
"d3",
"react",
"visx",
"bar"
]
}
File: packages/visx-demo/src/sandboxes/visx-barstack/package.json
{
"name": "@visx/demo-barstack",
"description": "Standalone visx stacked bar demo.",
"main": "index.tsx",
"private": true,
"dependencies": {
"@babel/runtime": "^7.8.4",
"@types/react": "^18",
"@types/react-dom": "^18",
"@visx/axis": "latest",
"@visx/event": "latest",
"@visx/grid": "latest",
"@visx/group": "latest",
"@visx/legend": "latest",
"@visx/mock-data": "latest",
"@visx/responsive": "latest",
"@visx/scale": "latest",
"@visx/shape": "latest",
"@visx/tooltip": "latest",
"@visx/vendor": "latest",
"react": "^18",
"react-dom": "^18",
"react-scripts-ts": "3.1.0",
"typescript": "^3"
},
"keywords": [
"visualization",
"d3",
"react",
"visx",
"barstack"
]
}
File: packages/visx-demo/src/sandboxes/visx-barstack-horizontal/package.json
{
"name": "@visx/demo-barstack-horizontal",
"description": "Standalone visx horizontal stacked bar demo.",
"main": "index.tsx",
"private": true,
"dependencies": {
"@babel/runtime": "^7.8.4",
"@types/react": "^18",
"@types/react-dom": "^18",
"@visx/axis": "latest",
"@visx/grid": "latest",
"@visx/group": "latest",
"@visx/legend": "latest",
"@visx/mock-data": "latest",
"@visx/responsive": "latest",
"@visx/scale": "latest",
"@visx/shape": "latest",
"@visx/tooltip": "latest",
"@visx/vendor": "latest",
"react": "^18",
"react-dom": "^18",
"react-scripts-ts": "3.1.0",
"typescript": "^3"
},
"keywords": [
"visualization",
"d3",
"react",
"visx",
"barstack"
]
}
File: packages/visx-demo/src/sandboxes/visx-brush/package.json
{
"name": "@visx/demo-brush",
"description": "Standalone visx brush demo.",
"main": "index.tsx",
"private": true,
"dependencies": {
"@babel/runtime": "^7.8.4",
"@types/react": "^18",
"@types/react-dom": "^18",
"@visx/axis": "latest",
"@visx/brush": "latest",
"@visx/curve": "latest",
"@visx/gradient": "latest",
"@visx/group": "latest",
"@visx/mock-data": "latest",
"@visx/pattern": "latest",
"@visx/responsive": "latest",
"@visx/scale": "latest",
"@visx/shape": "latest",
"@visx/vendor": "latest",
"react": "^18",
"react-dom": "^18",
"react-scripts-ts": "3.1.0",
"typescript": "^3"
},
"keywords": [
"visualization",
"d3",
"react",
"visx",
"brush",
"interaction"
]
}
File: packages/visx-demo/src/sandboxes/visx-chord/package.json
{
"name": "@visx/demo-chord",
"description": "Standalone visx chord demo.",
"main": "index.tsx",
"private": true,
"dependencies": {
"@babel/runtime": "^7.8.4",
"@types/react": "^18",
"@types/react-dom": "^18",
"@visx/chord": "latest",
"@visx/gradient": "latest",
"@visx/group": "latest",
"@visx/responsive": "latest",
"@visx/scale": "latest",
"@visx/shape": "latest",
"react": "^18",
"react-dom": "^18",
"react-scripts-ts": "3.1.0",
"typescript": "^3"
},
"keywords": [
"visualization",
"d3",
"react",
"visx"
]
}
File: packages/visx-demo/src/sandboxes/visx-curve/package.json
{
"name": "@visx/demo-curve",
"description": "Standalone visx curve demo.",
"main": "index.tsx",
"private": true,
"dependencies": {
"@babel/runtime": "^7.8.4",
"@types/react": "^18",
"@types/react-dom": "^18",
"@visx/curve": "latest",
"@visx/gradient": "latest",
"@visx/group": "latest",
"@visx/marker": "latest",
"@visx/mock-data": "latest",
"@visx/responsive": "latest",
"@visx/scale": "latest",
"@visx/shape": "latest",
"@visx/vendor": "latest",
"react": "^18",
"react-dom": "^18",
"react-scripts-ts": "3.1.0",
"typescript": "^3"
},
"keywords": [
"visualization",
"d3",
"react",
"visx",
"curve",
"interpolate"
]
}
File: packages/visx-demo/src/sandboxes/visx-delaunay-triangulation/package.json
{
"name": "@visx/demo-delaunay-triangulation",
"description": "Standalone visx delaunay triangulation demo.",
"main": "index.tsx",
"private": true,
"dependencies": {
"@babel/runtime": "^7.8.4",
"@types/react": "^18",
"@types/react-dom": "^18",
"@visx/clip-path": "latest",
"@visx/delaunay": "latest",
"@visx/event": "latest",
"@visx/gradient": "latest",
"@visx/group": "latest",
"@visx/mock-data": "latest",
"@visx/responsive": "latest",
"react": "^18",
"react-dom": "^18",
"react-scripts-ts": "3.1.0",
"typescript": "^3"
},
"keywords": [
"visualization",
"d3",
"react",
"visx",
"delaunay",
"triangulation"
]
}
File: packages/visx-demo/src/sandboxes/visx-delaunay-voronoi/package.json
{
"name": "@visx/demo-delaunay-voronoi",
"description": "Standalone @visx/delaunay voronoi demo.",
"main": "index.tsx",
"private": true,
"dependencies": {
"@babel/runtime": "^7.8.4",
"@types/react": "^18",
"@types/react-dom": "^18",
"@visx/clip-path": "latest",
"@visx/delaunay": "latest",
"@visx/event": "latest",
"@visx/gradient": "latest",
"@visx/group": "latest",
"@visx/mock-data": "latest",
"@visx/responsive": "latest",
"react": "^18",
"react-dom": "^18",
"react-scripts-ts": "3.1.0",
"typescript": "^3"
},
"keywords": [
"visualization",
"d3",
"react",
"visx",
"voronoi",
"delaunay"
]
}
File: packages/visx-demo/src/sandboxes/visx-dendrogram/package.json
{
"name": "@visx/demo-dendrogram",
"description": "Standalone visx dendrogram demo.",
"main": "index.tsx",
"private": true,
"dependencies": {
"@babel/runtime": "^7.8.4",
"@types/react": "^18",
"@types/react-dom": "^18",
"@visx/gradient": "latest",
"@visx/group": "latest",
"@visx/hierarchy": "latest",
"@visx/responsive": "latest",
"@visx/shape": "latest",
"react": "^18",
"react-dom": "^18",
"react-scripts-ts": "3.1.0",
"typescript": "^3"
},
"keywords": [
"visualization",
"d3",
"react",
"visx",
"hierarchy",
"dendrogram"
]
}
File: packages/visx-demo/src/sandboxes/visx-dots/package.json
{
"name": "@visx/demo-dots",
"description": "Standalone visx scatterplot demo.",
"main": "index.tsx",
"private": true,
"dependencies": {
"@babel/runtime": "^7.8.4",
"@types/react": "^18",
"@types/react-dom": "^18",
"@visx/event": "latest",
"@visx/gradient": "latest",
"@visx/group": "latest",
"@visx/mock-data": "latest",
"@visx/responsive": "latest",
"@visx/scale": "latest",
"@visx/shape": "latest",
"@visx/tooltip": "latest",
"@visx/voronoi": "latest",
"react": "^18",
"react-dom": "^18",
"react-scripts-ts": "3.1.0",
"typescript": "^3"
},
"keywords": [
"visualization",
"d3",
"react",
"visx",
"visualization"
]
}
File: packages/visx-demo/src/sandboxes/visx-drag-i/package.json
{
"name": "@visx/demo-drag-i",
"description": "Standalone visx drag demo.",
"main": "index.tsx",
"private": true,
"dependencies": {
"@babel/runtime": "^7.8.4",
"@types/react": "^18",
"@types/react-dom": "^18",
"@visx/drag": "latest",
"@visx/gradient": "latest",
"@visx/mock-data": "latest",
"@visx/responsive": "latest",
"@visx/scale": "latest",
"react": "^18",
"react-dom": "^18",
"react-scripts-ts": "3.1.0",
"typescript": "^3"
},
"keywords": [
"visualization",
"d3",
"react",
"visx",
"drag"
]
}
File: packages/visx-demo/src/sandboxes/visx-drag-ii/package.json
{
"name": "@visx/demo-drag-ii",
"description": "Standalone visx drag demo.",
"main": "index.tsx",
"private": true,
"dependencies": {
"@babel/runtime": "^7.8.4",
"@types/react": "^18",
"@types/react-dom": "^18",
"@visx/curve": "latest",
"@visx/drag": "latest",
"@visx/gradient": "latest",
"@visx/responsive": "latest",
"@visx/shape": "latest",
"react": "^18",
"react-dom": "^18",
"react-scripts-ts": "3.1.0",
"typescript": "^3"
},
"keywords": [
"visualization",
"d3",
"react",
"visx",
"drag",
"draw"
]
}
File: packages/visx-demo/src/sandboxes/visx-geo-albers-usa/package.json
{
"name": "@visx/demo-geo-albers-usa",
"description": "Standalone visx geo-albers-usa demo.",
"main": "index.tsx",
"private": true,
"dependencies": {
"@babel/runtime": "^7.8.4",
"@types/react": "^18",
"@types/react-dom": "^18",
"@visx/geo": "latest",
"@visx/responsive": "latest",
"@visx/vendor": "latest",
"react": "^18",
"react-dom": "^18",
"react-scripts-ts": "3.1.0",
"topojson-client": "^3.1.0",
"typescript": "^3"
},
"keywords": [
"visualization",
"d3",
"react",
"visx",
"geojson",
"geo",
"mercator",
"map"
]
}
File: packages/visx-demo/src/sandboxes/visx-geo-albers-usa/us-abbr.json
{
"01": "AL",
"02": "AK",
"60": "AS",
"04": "AZ",
"05": "AR",
"06": "CA",
"08": "CO",
"09": "CT",
"10": "DE",
"12": "FL",
"64": "FM",
"13": "GA",
"66": "GU",
"15": "HI",
"16": "ID",
"17": "IL",
"18": "IN",
"19": "IA",
"20": "KS",
"21": "KY",
"22": "LA",
"23": "ME",
"68": "MH",
"24": "MD",
"25": "MA",
"26": "MI",
"27": "MN",
"28": "MS",
"29": "MO",
"30": "MT",
"31": "NE",
"32": "NV",
"33": "NH",
"34": "NJ",
"35": "NM",
"36": "NY",
"37": "NC",
"38": "ND",
"69": "MP",
"39": "OH",
"40": "OK",
"41": "OR",
"70": "PW",
"42": "PA",
"72": "PR",
"44": "RI",
"45": "SC",
"46": "SD",
"47": "TN",
"48": "TX",
"74": "UM",
"49": "UT",
"50": "VT",
"51": "VA",
"78": "VI",
"53": "WA",
"54": "WV",
"55": "WI",
"56": "WY"
}
File: packages/visx-demo/src/sandboxes/visx-geo-custom/package.json
{
"name": "@visx/demo-geo-custom",
"description": "Standalone visx geo-custom demo.",
"main": "index.tsx",
"private": true,
"dependencies": {
"@babel/runtime": "^7.8.4",
"@types/react": "^18",
"@types/react-dom": "^18",
"@visx/geo": "latest",
"@visx/responsive": "latest",
"@visx/scale": "latest",
"@visx/vendor": "latest",
"@visx/zoom": "latest",
"react": "^18",
"react-dom": "^18",
"react-scripts-ts": "3.1.0",
"topojson-client": "3.1.0",
"typescript": "^3"
},
"keywords": [
"visualization",
"d3",
"react",
"visx",
"geo",
"maps",
"projection"
]
}
File: packages/visx-demo/src/sandboxes/visx-geo-mercator/package.json
{
"name": "@visx/demo-geo-mercator",
"description": "Standalone visx geo-mercator demo.",
"main": "index.tsx",
"private": true,
"dependencies": {
"@babel/runtime": "^7.8.4",
"@types/react": "^18",
"@types/react-dom": "^18",
"@visx/geo": "latest",
"@visx/responsive": "latest",
"@visx/scale": "latest",
"react": "^18",
"react-dom": "^18",
"react-scripts-ts": "3.1.0",
"topojson-client": "^3.1.0",
"typescript": "^3"
},
"keywords": [
"visualization",
"d3",
"react",
"visx",
"geojson",
"geo",
"mercator",
"map"
]
}
File: packages/visx-demo/src/sandboxes/visx-glyph/package.json
{
"name": "@visx/demo-glyph",
"description": "Standalone visx glyph demo.",
"main": "index.tsx",
"private": true,
"dependencies": {
"@babel/runtime": "^7.8.4",
"@types/react": "^18",
"@types/react-dom": "^18",
"@visx/curve": "latest",
"@visx/glyph": "latest",
"@visx/group": "latest",
"@visx/mock-data": "latest",
"@visx/responsive": "latest",
"@visx/scale": "latest",
"@visx/shape": "latest",
"react": "^18",
"react-dom": "^18",
"react-scripts-ts": "3.1.0",
"typescript": "^3"
},
"keywords": [
"visualization",
"d3",
"react",
"visx",
"svg",
"glyph"
]
}
File: packages/visx-demo/src/sandboxes/visx-gradient/package.json
{
"name": "@visx/demo-gradient",
"description": "Standalone visx gradient demo.",
"main": "index.tsx",
"private": true,
"dependencies": {
"@babel/runtime": "^7.8.4",
"@types/react": "^18",
"@types/react-dom": "^18",
"@visx/gradient": "latest",
"@visx/responsive": "latest",
"@visx/shape": "latest",
"react": "^18",
"react-dom": "^18",
"react-scripts-ts": "3.1.0",
"typescript": "^3"
},
"keywords": [
"visualization",
"d3",
"react",
"visx",
"svg",
"gradient"
]
}
File: packages/visx-demo/src/sandboxes/visx-heatmap/package.json
{
"name": "@visx/demo-heatmap",
"description": "Standalone visx heatmap demo.",
"main": "index.tsx",
"private": true,
"dependencies": {
"@babel/runtime": "^7.8.4",
"@types/react": "^18",
"@types/react-dom": "^18",
"@visx/group": "latest",
"@visx/heatmap": "latest",
"@visx/mock-data": "latest",
"@visx/responsive": "latest",
"@visx/scale": "latest",
"react": "^18",
"react-dom": "^18",
"react-scripts-ts": "3.1.0",
"typescript": "^3"
},
"keywords": [
"visualization",
"d3",
"react",
"visx",
"heatmap"
]
}
File: packages/visx-demo/src/sandboxes/visx-legend/package.json
{
"name": "@visx/demo-legend",
"description": "Standalone visx legends demo.",
"main": "index.tsx",
"private": true,
"dependencies": {
"@babel/runtime": "^7.8.4",
"@types/react": "^18",
"@types/react-dom": "^18",
"@visx/glyph": "latest",
"@visx/legend": "latest",
"@visx/scale": "latest",
"@visx/vendor": "latest",
"react": "^18",
"react-dom": "^18",
"react-scripts-ts": "3.1.0",
"typescript": "^3"
},
"keywords": [
"visualization",
"d3",
"react",
"visx",
"legend"
]
}
File: packages/visx-demo/src/sandboxes/visx-linktypes/package.json
{
"name": "@visx/demo-linktypes",
"description": "Standalone visx link types demo.",
"main": "index.tsx",
"private": true,
"dependencies": {
"@babel/runtime": "^7.8.4",
"@types/react": "^18",
"@types/react-dom": "^18",
"@visx/gradient": "latest",
"@visx/group": "latest",
"@visx/hierarchy": "latest",
"@visx/responsive": "latest",
"@visx/shape": "latest",
"d3-shape": "3.2.0",
"react": "^18",
"react-dom": "^18",
"react-scripts-ts": "3.1.0",
"typescript": "^3"
},
"keywords": [
"visualization",
"d3",
"react",
"visx",
"link",
"shape"
]
}
File: packages/visx-demo/src/sandboxes/visx-network/package.json
{
"name": "@visx/demo-network",
"description": "Standalone visx network demo.",
"main": "index.tsx",
"private": true,
"dependencies": {
"@babel/runtime": "^7.8.4",
"@types/react": "^18",
"@types/react-dom": "^18",
"@visx/responsive": "latest",
"@visx/network": "latest",
"react": "^18",
"react-dom": "^18",
"react-scripts-ts": "3.1.0",
"typescript": "^3"
},
"keywords": [
"visualization",
"d3",
"react",
"visx",
"network"
]
}
File: packages/visx-demo/src/sandboxes/visx-pack/package.json
{
"name": "@visx/demo-pack",
"description": "Standalone visx hierarchy pack demo.",
"main": "index.tsx",
"private": true,
"dependencies": {
"@babel/runtime": "^7.8.4",
"@types/react": "^18",
"@types/react-dom": "^18",
"@visx/group": "latest",
"@visx/hierarchy": "latest",
"@visx/mock-data": "latest",
"@visx/responsive": "latest",
"@visx/scale": "latest",
"react": "^18",
"react-dom": "^18",
"react-scripts-ts": "3.1.0",
"typescript": "^3"
},
"keywords": [
"visualization",
"d3",
"react",
"visx",
"hierarchy",
"pack"
]
}
File: packages/visx-demo/src/sandboxes/visx-pattern/package.json
{
"name": "@visx/demo-pattern",
"description": "Standalone visx pattern demo.",
"main": "index.tsx",
"private": true,
"dependencies": {
"@babel/runtime": "^7.8.4",
"@types/react": "^18",
"@types/react-dom": "^18",
"@visx/group": "latest",
"@visx/pattern": "latest",
"@visx/responsive": "latest",
"@visx/shape": "latest",
"react": "^18",
"react-dom": "^18",
"react-scripts-ts": "3.1.0",
"typescript": "^3"
},
"keywords": [
"visualization",
"d3",
"react",
"visx"
]
}
File: packages/visx-demo/src/sandboxes/visx-polygons/package.json
{
"name": "@visx/demo-polygons",
"description": "Standalone visx polygons demo.",
"main": "index.tsx",
"private": true,
"dependencies": {
"@babel/runtime": "^7.8.4",
"@types/react": "^18",
"@types/react-dom": "^18",
"@visx/gradient": "latest",
"@visx/group": "latest",
"@visx/responsive": "latest",
"@visx/scale": "latest",
"@visx/shape": "latest",
"react": "^18",
"react-dom": "^18",
"react-scripts-ts": "3.1.0",
"typescript": "^3"
},
"keywords": [
"visualization",
"d3",
"react",
"visx",
"polygon",
"shape"
]
}
File: packages/visx-demo/src/sandboxes/visx-radar/package.json
{
"name": "@visx/demo-radar",
"description": "Standalone visx radar chart demo.",
"main": "index.tsx",
"private": true,
"dependencies": {
"@babel/runtime": "^7.8.4",
"@types/react": "^18",
"@types/react-dom": "^18",
"@visx/group": "latest",
"@visx/mock-data": "latest",
"@visx/responsive": "latest",
"@visx/point": "latest",
"@visx/scale": "latest",
"@visx/shape": "latest",
"react": "^18",
"react-dom": "^18",
"react-scripts-ts": "3.1.0",
"typescript": "^3"
},
"keywords": [
"visualization",
"d3",
"react",
"visx",
"radar"
]
}
File: packages/visx-demo/src/sandboxes/visx-radial-bars/package.json
{
"name": "@visx/demo-radial-bars",
"description": "Standalone visx radial bars demo.",
"main": "index.tsx",
"private": true,
"dependencies": {
"@babel/runtime": "^7.8.4",
"@types/react": "^18",
"@types/react-dom": "^18",
"@visx/gradient": "latest",
"@visx/group": "latest",
"@visx/mock-data": "latest",
"@visx/responsive": "latest",
"@visx/scale": "latest",
"@visx/shape": "latest",
"@visx/text": "latest",
"react": "^18",
"react-dom": "^18",
"react-scripts-ts": "3.1.0",
"typescript": "^3"
},
"keywords": [
"visualization",
"d3",
"react",
"visx",
"bar"
]
}
File: packages/visx-demo/src/sandboxes/visx-responsive/package.json
{
"name": "@visx/demo-responsive",
"description": "Standalone @visx/responsive demo.",
"main": "index.tsx",
"private": true,
"dependencies": {
"@babel/runtime": "^7.8.4",
"@types/react": "^18",
"@types/react-dom": "^18",
"@visx/group": "latest",
"@visx/mock-data": "latest",
"@visx/responsive": "latest",
"@visx/scale": "latest",
"@visx/shape": "latest",
"@visx/vendor": "latest",
"react": "^18",
"react-dom": "^18",
"react-scripts-ts": "3.1.0",
"typescript": "^3"
},
"keywords": [
"visualization",
"d3",
"react",
"visx"
]
}
File: packages/visx-demo/src/sandboxes/visx-sankey/energy.json
{"nodes":[{"name":"Agricultural 'waste'"},{"name":"Bio-conversion"},{"name":"Liquid"},{"name":"Losses"},{"name":"Solid"},{"name":"Gas"},{"name":"Biofuel imports"},{"name":"Biomass imports"},{"name":"Coal imports"},{"name":"Coal"},{"name":"Coal reserves"},{"name":"District heating"},{"name":"Industry"},{"name":"Heating and cooling - commercial"},{"name":"Heating and cooling - homes"},{"name":"Electricity grid"},{"name":"Over generation / exports"},{"name":"H2 conversion"},{"name":"Road transport"},{"name":"Agriculture"},{"name":"Rail transport"},{"name":"Lighting & appliances - commercial"},{"name":"Lighting & appliances - homes"},{"name":"Gas imports"},{"name":"Ngas"},{"name":"Gas reserves"},{"name":"Thermal generation"},{"name":"Geothermal"},{"name":"H2"},{"name":"Hydro"},{"name":"International shipping"},{"name":"Domestic aviation"},{"name":"International aviation"},{"name":"National navigation"},{"name":"Marine algae"},{"name":"Nuclear"},{"name":"Oil imports"},{"name":"Oil"},{"name":"Oil reserves"},{"name":"Other waste"},{"name":"Pumped heat"},{"name":"Solar PV"},{"name":"Solar Thermal"},{"name":"Solar"},{"name":"Tidal"},{"name":"UK land based bioenergy"},{"name":"Wave"},{"name":"Wind"}],"links":[{"source":0,"target":1,"value":124.729},{"source":1,"target":2,"value":0.597},{"source":1,"target":3,"value":26.862},{"source":1,"target":4,"value":280.322},{"source":1,"target":5,"value":81.144},{"source":6,"target":2,"value":35},{"source":7,"target":4,"value":35},{"source":8,"target":9,"value":11.606},{"source":10,"target":9,"value":63.965},{"source":9,"target":4,"value":75.571},{"source":11,"target":12,"value":10.639},{"source":11,"target":13,"value":22.505},{"source":11,"target":14,"value":46.184},{"source":15,"target":16,"value":104.453},{"source":15,"target":14,"value":113.726},{"source":15,"target":17,"value":27.14},{"source":15,"target":12,"value":342.165},{"source":15,"target":18,"value":37.797},{"source":15,"target":19,"value":4.412},{"source":15,"target":13,"value":40.858},{"source":15,"target":3,"value":56.691},{"source":15,"target":20,"value":7.863},{"source":15,"target":21,"value":90.008},{"source":15,"target":22,"value":93.494},{"source":23,"target":24,"value":40.719},{"source":25,"target":24,"value":82.233},{"source":5,"target":13,"value":0.129},{"source":5,"target":3,"value":1.401},{"source":5,"target":26,"value":151.891},{"source":5,"target":19,"value":2.096},{"source":5,"target":12,"value":48.58},{"source":27,"target":15,"value":7.013},{"source":17,"target":28,"value":20.897},{"source":17,"target":3,"value":6.242},{"source":28,"target":18,"value":20.897},{"source":29,"target":15,"value":6.995},{"source":2,"target":12,"value":121.066},{"source":2,"target":30,"value":128.69},{"source":2,"target":18,"value":135.835},{"source":2,"target":31,"value":14.458},{"source":2,"target":32,"value":206.267},{"source":2,"target":19,"value":3.64},{"source":2,"target":33,"value":33.218},{"source":2,"target":20,"value":4.413},{"source":34,"target":1,"value":4.375},{"source":24,"target":5,"value":122.952},{"source":35,"target":26,"value":839.978},{"source":36,"target":37,"value":504.287},{"source":38,"target":37,"value":107.703},{"source":37,"target":2,"value":611.99},{"source":39,"target":4,"value":56.587},{"source":39,"target":1,"value":77.81},{"source":40,"target":14,"value":193.026},{"source":40,"target":13,"value":70.672},{"source":41,"target":15,"value":59.901},{"source":42,"target":14,"value":19.263},{"source":43,"target":42,"value":19.263},{"source":43,"target":41,"value":59.901},{"source":4,"target":19,"value":0.882},{"source":4,"target":26,"value":400.12},{"source":4,"target":12,"value":46.477},{"source":26,"target":15,"value":525.531},{"source":26,"target":3,"value":787.129},{"source":26,"target":11,"value":79.329},{"source":44,"target":15,"value":9.452},{"source":45,"target":1,"value":182.01},{"source":46,"target":15,"value":19.013},{"source":47,"target":15,"value":289.366}]}
File: packages/visx-demo/src/sandboxes/visx-sankey/package.json
{
"name": "@visx/demo-sankey",
"description": "Standalone visx sankey demo.",
"main": "index.tsx",
"private": true,
"dependencies": {
"@babel/runtime": "^7.8.4",
"@types/react": "^18",
"@types/react-dom": "^18" ,
"@visx/event": "latest",
"@visx/group": "latest",
"@visx/responsive": "latest",
"@visx/sankey": "latest",
"@visx/shape": "latest",
"@visx/tooltip": "latest",
"react": "^18",
"react-dom": "^18",
"react-scripts-ts": "3.1.0",
"typescript": "^3"
},
"keywords": [
"visualization",
"d3",
"react",
"visx",
"sankey"
]
}
File: packages/visx-demo/src/sandboxes/visx-shape-line-radial/package.json
{
"name": "@visx/demo-shape-line-radial",
"description": "Standalone visx line radial demo.",
"main": "index.tsx",
"private": true,
"dependencies": {
"@babel/runtime": "^7.8.4",
"@types/react": "^18",
"@types/react-dom": "^18",
"@visx/axis": "latest",
"@visx/curve": "latest",
"@visx/gradient": "latest",
"@visx/group": "latest",
"@visx/grid": "latest",
"@visx/mock-data": "latest",
"@visx/responsive": "latest",
"@visx/scale": "latest",
"@visx/shape": "latest",
"react": "^18",
"react-dom": "^18",
"react-scripts-ts": "3.1.0",
"@react-spring/web": "^10.0.3",
"typescript": "^3"
},
"keywords": [
"visualization",
"d3",
"react",
"visx",
"shape",
"radial",
"line"
]
}
File: packages/visx-demo/src/sandboxes/visx-shape-pie/package.json
{
"name": "@visx/demo-shape-pie",
"description": "Standalone visx pie demo.",
"main": "index.tsx",
"private": true,
"dependencies": {
"@babel/runtime": "^7.8.4",
"@types/react": "^18",
"@types/react-dom": "^18",
"@visx/gradient": "latest",
"@visx/group": "latest",
"@visx/mock-data": "latest",
"@visx/responsive": "latest",
"@visx/scale": "latest",
"@visx/shape": "latest",
"react": "^18",
"react-dom": "^18",
"react-scripts-ts": "3.1.0",
"@react-spring/web": "^10.0.3",
"typescript": "^3"
},
"keywords": [
"visualization",
"d3",
"react",
"visx",
"pie",
"shape",
"donut"
]
}
File: packages/visx-demo/src/sandboxes/visx-shape-splitlinepath/package.json
{
"name": "@visx/demo-shape-splitlinepath",
"description": "Standalone visx splitlinepath demo.",
"main": "index.tsx",
"private": true,
"dependencies": {
"@babel/runtime": "^7.8.4",
"@types/react": "^18",
"@types/react-dom": "^18",
"@visx/curve": "latest",
"@visx/gradient": "latest",
"@visx/responsive": "latest",
"@visx/scale": "latest",
"@visx/shape": "latest",
"react": "^18",
"react-dom": "^18",
"react-scripts-ts": "3.1.0",
"typescript": "^3"
},
"keywords": [
"visualization",
"d3",
"react",
"visx",
"splitline"
]
}
File: packages/visx-demo/src/sandboxes/visx-stacked-areas/package.json
{
"name": "@visx/demo-stacked-areas",
"description": "Standalone visx stacked area demo.",
"main": "index.tsx",
"private": true,
"dependencies": {
"@babel/runtime": "^7.8.4",
"@types/react": "^18",
"@types/react-dom": "^18",
"@visx/gradient": "latest",
"@visx/mock-data": "latest",
"@visx/responsive": "latest",
"@visx/scale": "latest",
"@visx/shape": "latest",
"@visx/vendor": "latest",
"react": "^18",
"react-dom": "^18",
"react-scripts-ts": "3.1.0",
"typescript": "^3"
},
"keywords": [
"visualization",
"d3",
"react",
"visx",
"stackedarea"
]
}
File: packages/visx-demo/src/sandboxes/visx-stats/package.json
{
"name": "@visx/demo-stats",
"description": "Standalone visx stats demo.",
"main": "index.tsx",
"private": true,
"dependencies": {
"@babel/runtime": "^7.8.4",
"@types/react": "^18",
"@types/react-dom": "^18",
"@visx/gradient": "latest",
"@visx/group": "latest",
"@visx/mock-data": "latest",
"@visx/pattern": "latest",
"@visx/responsive": "latest",
"@visx/scale": "latest",
"@visx/stats": "latest",
"@visx/tooltip": "latest",
"react": "^18",
"react-dom": "^18",
"react-scripts-ts": "3.1.0",
"typescript": "^3"
},
"keywords": [
"visualization",
"d3",
"react",
"visx",
"stats",
"boxplot",
"violin plot"
]
}
File: packages/visx-demo/src/sandboxes/visx-streamgraph/package.json
{
"name": "@visx/demo-streamgraph",
"description": "Standalone visx streamgraph demo.",
"main": "index.tsx",
"private": true,
"dependencies": {
"@babel/runtime": "^7.8.4",
"@types/react": "^18",
"@types/react-dom": "^18",
"@visx/mock-data": "latest",
"@visx/pattern": "latest",
"@visx/responsive": "latest",
"@visx/scale": "latest",
"@visx/shape": "latest",
"@visx/vendor": "latest",
"react": "^18",
"react-dom": "^18",
"react-scripts-ts": "3.1.0",
"@react-spring/web": "^10.0.3",
"typescript": "^3"
},
"keywords": [
"visualization",
"d3",
"react",
"visx",
"streamgraph",
"react-spring"
]
}
File: packages/visx-demo/src/sandboxes/visx-threshold/package.json
{
"name": "@visx/demo-threshold",
"description": "Standalone visx threshold demo.",
"main": "index.tsx",
"private": true,
"dependencies": {
"@babel/runtime": "^7.8.4",
"@types/react": "^18",
"@types/react-dom": "^18",
"@visx/axis": "latest",
"@visx/curve": "latest",
"@visx/grid": "latest",
"@visx/group": "latest",
"@visx/mock-data": "latest",
"@visx/responsive": "latest",
"@visx/scale": "latest",
"@visx/shape": "latest",
"@visx/threshold": "latest",
"react": "^18",
"react-dom": "^18",
"react-scripts-ts": "3.1.0",
"typescript": "^3"
},
"keywords": [
"visualization",
"d3",
"react",
"visx",
"threshold"
]
}
File: packages/visx-demo/src/sandboxes/visx-tooltip/package.json
{
"name": "@visx/demo-tooltip",
"description": "Standalone visx tooltip demo.",
"main": "index.tsx",
"private": true,
"dependencies": {
"@babel/runtime": "^7.8.4",
"@types/react": "^18",
"@types/react-dom": "^18",
"@visx/responsive": "latest",
"@visx/tooltip": "latest",
"react": "^18",
"react-dom": "^18",
"react-scripts-ts": "3.1.0",
"typescript": "^3"
},
"keywords": [
"visualization",
"d3",
"react",
"visx"
]
}
File: packages/visx-demo/src/sandboxes/visx-tree/package.json
{
"name": "@visx/demo-tree",
"description": "Standalone visx tree demo.",
"main": "index.tsx",
"private": true,
"dependencies": {
"@babel/runtime": "^7.8.4",
"@types/react": "^18",
"@types/react-dom": "^18",
"@visx/gradient": "latest",
"@visx/group": "latest",
"@visx/hierarchy": "latest",
"@visx/responsive": "latest",
"@visx/shape": "latest",
"react": "^18",
"react-dom": "^18",
"react-scripts-ts": "3.1.0",
"typescript": "^3"
},
"keywords": [
"visualization",
"d3",
"react",
"visx",
"hierarchy",
"tree"
]
}
File: packages/visx-demo/src/sandboxes/visx-treemap/package.json
{
"name": "@visx/demo-treemap",
"description": "Standalone visx treemap demo.",
"main": "index.tsx",
"private": true,
"dependencies": {
"@babel/runtime": "^7.8.4",
"@types/react": "^18",
"@types/react-dom": "^18",
"@visx/group": "latest",
"@visx/hierarchy": "latest",
"@visx/mock-data": "latest",
"@visx/responsive": "latest",
"@visx/scale": "latest",
"react": "^18",
"react-dom": "^18",
"react-scripts-ts": "3.1.0",
"typescript": "^3"
},
"keywords": [
"visualization",
"d3",
"react",
"visx",
"treemap",
"hierarchy"
]
}
File: packages/visx-demo/src/sandboxes/visx-voronoi/package.json
{
"name": "@visx/demo-voronoi",
"description": "Standalone visx voronoi demo.",
"main": "index.tsx",
"private": true,
"dependencies": {
"@babel/runtime": "^7.8.4",
"@types/react": "^18",
"@types/react-dom": "^18",
"@visx/clip-path": "latest",
"@visx/event": "latest",
"@visx/gradient": "latest",
"@visx/group": "latest",
"@visx/mock-data": "latest",
"@visx/responsive": "latest",
"@visx/voronoi": "latest",
"react": "^18",
"react-dom": "^18",
"react-scripts-ts": "3.1.0",
"typescript": "^3"
},
"keywords": [
"visualization",
"d3",
"react",
"visx",
"voronoi"
]
}
File: packages/visx-demo/src/sandboxes/visx-wordcloud/package.json
{
"name": "@visx/demo-wordcloud",
"description": "Standalone visx wordcloud demo.",
"main": "index.tsx",
"private": true,
"dependencies": {
"@visx/responsive":"latest",
"@visx/scale":"latest",
"@visx/text":"latest",
"@visx/wordcloud":"latest",
"react": "^18",
"react-dom": "^18"
},
"devDependencies": {
"@types/react": "^18",
"@types/react-dom": "^18",
"typescript": "^3"
},
"keywords": [
"visualization",
"d3",
"react",
"visx"
]
}
File: packages/visx-demo/src/sandboxes/visx-xychart/package.json
{
"name": "@visx/demo-xychart",
"description": "Standalone visx xychart demo.",
"main": "index.tsx",
"private": true,
"dependencies": {
"@babel/runtime": "^7.8.4",
"@types/react": "^18",
"@types/react-dom": "^18",
"@visx/curve": "1.0.0",
"@visx/glyph": "latest",
"@visx/mock-data": "latest",
"@visx/pattern": "latest",
"@visx/react-spring": "latest",
"@visx/responsive": "latest",
"@visx/xychart": "latest",
"react": "^18",
"react-dom": "^18",
"react-scripts-ts": "3.1.0",
"@react-spring/web": "^10.0.3",
"typescript": "^3"
},
"keywords": [
"visualization",
"d3",
"react",
"visx"
]
}
File: packages/visx-demo/src/sandboxes/visx-zoom-i/package.json
{
"name": "@visx/demo-zoom-i",
"description": "Standalone visx zoom demo.",
"main": "index.tsx",
"private": true,
"dependencies": {
"@babel/runtime": "^7.8.4",
"@types/react": "^18",
"@types/react-dom": "^18",
"@visx/clip-path": "latest",
"@visx/event": "latest",
"@visx/mock-data": "latest",
"@visx/responsive": "latest",
"@visx/scale": "latest",
"@visx/zoom": "latest",
"d3-scale-chromatic": "^3.1.0",
"react": "^18",
"react-dom": "^18",
"react-scripts-ts": "3.1.0",
"typescript": "^3"
},
"keywords": [
"visualization",
"d3",
"react",
"visx",
"zoom"
]
}
File: packages/visx-drag/Readme.md
@visx/drag
@visx/drag provides react components and hooks for making items within an interface (or chart)
draggable.
Installation
npm install --save @visx/dragFile: packages/visx-drag/package.json
{
"name": "@visx/drag",
"version": "4.0.0",
"description": "visx drag",
"sideEffects": false,
"main": "lib/index.js",
"module": "esm/index.js",
"types": "lib/index.d.ts",
"exports": {
".": {
"types": "./lib/index.d.ts",
"import": "./esm/index.js",
"require": "./lib/index.js"
}
},
"files": [
"lib",
"esm"
],
"repository": {
"type": "git",
"url": "git+https://github.com/airbnb/visx.git"
},
"keywords": [
"visx",
"react",
"d3",
"visualizations",
"charts"
],
"author": "@hshoff",
"license": "MIT",
"bugs": {
"url": "https://github.com/airbnb/visx/issues"
},
"homepage": "https://github.com/airbnb/visx#readme",
"publishConfig": {
"access": "public"
},
"peerDependencies": {
"@types/react": "^18.0.0 || ^19.0.0",
"react": "^18.0.0 || ^19.0.0"
},
"dependencies": {
"@visx/event": "workspace:",
"@visx/point": "workspace:"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
},
"devDependencies": {
"@types/react": "^19.0.0"
}
}
File: packages/visx-drag/tsconfig.json
{
"compilerOptions": {
"declarationDir": "lib",
"outDir": "lib",
"rootDir": "src"
},
"exclude": [
"lib",
"test"
],
"extends": "../../tsconfig.options.json",
"include": [
"src//*",
"types//",
"../../types/**/"
],
"references": [
{
"path": "../visx-event"
},
{
"path": "../visx-point"
}
]
}
File: packages/visx-drag/test/tsconfig.json
{
"compilerOptions": {
"composite": false,
"emitDeclarationOnly": false,
"noEmit": true,
"rootDir": ".",
"types": ["vitest/globals"]
},
"extends": "../../../tsconfig.options.json",
"include": ["/*", "../types//", "../../../types/**/"],
"references": [
{
"path": ".."
}
]
}
File: packages/visx-event/Readme.md
@visx/event
Installation
npm install --save @visx/eventUsage
@visx/event exports a utility localPoint that takes an SVG MouseEvent or TouchEvent as
input and returns a { x: number; y: number; } point coordinate (or null in the case the event
has no ownerSVGElement) within the coordinate system of the SVG. This makes placement of
tooltips, finding nearby datum, etc. easier.
Example:
import { localPoint } from '@visx/event';
<svg>
<SomeElement
{...}
onMouseMove={(event: MouseEvent) => {
const point = localPoint(event) || { x: 0, y: 0 };
// use coordinates ...
}}
/>
{...}
</svg>You may optionally pass a reference to the SVG node
import { useRef } from 'react';
import { localPoint } from '@visx/event';
const svgRef = useRef<SVGSVGElement>(null);
<svg ref={svgRef}>
<SomeElement
{...}
onMouseMove={(event: MouseEvent) => {
const point = localPoint(svgRef.current, event) || { x: 0, y: 0 };
// use coordinates ...
}}
/>
{...}
</svg>File: packages/visx-event/package.json
{
"name": "@visx/event",
"version": "4.0.0",
"description": "visx event",
"sideEffects": false,
"main": "lib/index.js",
"module": "esm/index.js",
"types": "lib/index.d.ts",
"exports": {
".": {
"types": "./lib/index.d.ts",
"import": "./esm/index.js",
"require": "./lib/index.js"
}
},
"files": [
"lib",
"esm"
],
"repository": {
"type": "git",
"url": "git+https://github.com/airbnb/visx.git"
},
"keywords": [
"visx",
"d3",
"react",
"visualizations",
"charts"
],
"author": "@hshoff",
"license": "MIT",
"bugs": {
"url": "https://github.com/airbnb/visx/issues"
},
"homepage": "https://github.com/airbnb/visx#readme",
"publishConfig": {
"access": "public"
},
"dependencies": {
"@visx/point": "workspace:*"
},
"peerDependencies": {
"@types/react": "^18.0.0 || ^19.0.0",
"react": "^18.0.0 || ^19.0.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
}
File: packages/visx-event/tsconfig.json
{
"compilerOptions": {
"declarationDir": "lib",
"outDir": "lib",
"rootDir": "src"
},
"exclude": [
"lib",
"test"
],
"extends": "../../tsconfig.options.json",
"include": [
"src//*",
"types//",
"../../types/**/"
],
"references": [
{
"path": "../visx-point"
}
]
}
File: packages/visx-event/test/tsconfig.json
{
"compilerOptions": {
"composite": false,
"emitDeclarationOnly": false,
"noEmit": true,
"rootDir": ".",
"types": ["vitest/globals"]
},
"extends": "../../../tsconfig.options.json",
"include": ["/*", "../types//", "../../../types/**/"],
"references": [
{
"path": ".."
}
]
}
File: packages/visx-geo/Readme.md
@visx/geo
The @visx/geo package provides react components for rendering common and custom geographic
projections. `` can be used to render preset projections
(projection='orthographic' | 'albers' | 'albersUsa' | 'mercator' | 'naturalEarth' | 'equalEarth')
along with configurable <Graticule />s lines. Convenience projections such as <Mercator /> are
also exported, along with <CustomProjection /> and <Graticule /> for full customization.
Installation
npm install --save @visx/geoFile: packages/visx-geo/package.json
{
"name": "@visx/geo",
"version": "4.0.0",
"description": "visx geo",
"sideEffects": false,
"main": "lib/index.js",
"module": "esm/index.js",
"types": "lib/index.d.ts",
"exports": {
".": {
"types": "./lib/index.d.ts",
"import": "./esm/index.js",
"require": "./lib/index.js"
}
},
"files": [
"lib",
"esm"
],
"repository": {
"type": "git",
"url": "git+https://github.com/airbnb/visx.git"
},
"keywords": [
"visx",
"react",
"d3",
"visualizations",
"charts",
"geo"
],
"author": "@nschnierer",
"license": "MIT",
"bugs": {
"url": "https://github.com/airbnb/visx/issues"
},
"homepage": "https://github.com/airbnb/visx#readme",
"dependencies": {
"@types/geojson": "",
"@visx/group": "workspace:",
"@visx/vendor": "workspace:*",
"classnames": "^2.3.1"
},
"devDependencies": {
"@types/react": "^19.0.0",
"@types/topojson-client": "^3.1.5",
"topojson-client": "^3.1.0"
},
"peerDependencies": {
"@types/react": "^18.0.0 || ^19.0.0",
"react": "^18.0.0 || ^19.0.0"
},
"publishConfig": {
"access": "public"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
}
File: packages/visx-geo/tsconfig.json
{
"compilerOptions": {
"declarationDir": "lib",
"outDir": "lib",
"rootDir": "src"
},
"exclude": [
"lib",
"test"
],
"extends": "../../tsconfig.options.json",
"include": [
"src//*",
"types//",
"../../types/**/"
],
"references": [
{
"path": "../visx-group"
},
{
"path": "../visx-vendor"
}
]
}
File: packages/visx-geo/test/topo.json
{
"type": "Topology",
"objects": {
"collection": {
"type": "GeometryCollection",
"geometries": [
{
"type": "Polygon",
"arcs": [[0]],
"id": "poly1"
},
{
"type": "Polygon",
"arcs": [[1]],
"id": "poly2"
}
]
}
},
"arcs": [
[
[3598, 6571],
[-3598, -6571],
[5188, 0],
[-1590, 6571]
],
[
[7823, 9999],
[-2008, -9999],
[4184, 0],
[-2176, 9999]
]
],
"bbox": [-87.2698974609375, 21.616579336740607, -45.2581787109375, 42.68243539838623],
"transform": {
"scale": [0.00420159203420342, 0.002106796285793142],
"translate": [-87.2698974609375, 21.616579336740607]
}
}
File: packages/visx-geo/test/tsconfig.json
{
"compilerOptions": {
"composite": false,
"emitDeclarationOnly": false,
"noEmit": true,
"rootDir": ".",
"types": ["vitest/globals"]
},
"extends": "../../../tsconfig.options.json",
"include": ["/*", "../types//", "../../../types/**/"],
"references": [
{
"path": ".."
}
]
}
File: packages/visx-glyph/Readme.md
@visx/glyph
Glyphs are small marks or symbols that you can use in your charts. Example:
https://airbnb.io/visx/glyphs
Installation
npm install --save @visx/glyphFile: packages/visx-glyph/package.json
{
"name": "@visx/glyph",
"version": "4.0.0",
"description": "visx glyph",
"sideEffects": false,
"main": "lib/index.js",
"module": "esm/index.js",
"types": "lib/index.d.ts",
"exports": {
".": {
"types": "./lib/index.d.ts",
"import": "./esm/index.js",
"require": "./lib/index.js"
}
},
"files": [
"lib",
"esm"
],
"repository": {
"type": "git",
"url": "git+https://github.com/airbnb/visx.git"
},
"keywords": [
"visx",
"react",
"d3",
"visualizations",
"charts"
],
"author": "@hshoff",
"license": "MIT",
"bugs": {
"url": "https://github.com/airbnb/visx/issues"
},
"homepage": "https://github.com/airbnb/visx#readme",
"publishConfig": {
"access": "public"
},
"peerDependencies": {
"@types/react": "^18.0.0 || ^19.0.0",
"react": "^18.0.0 || ^19.0.0"
},
"dependencies": {
"@visx/group": "workspace:",
"@visx/vendor": "workspace:",
"classnames": "^2.3.1"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
},
"devDependencies": {
"@types/react": "^19.0.0"
}
}
File: packages/visx-glyph/tsconfig.json
{
"compilerOptions": {
"declarationDir": "lib",
"outDir": "lib",
"rootDir": "src"
},
"exclude": [
"lib",
"test"
],
"extends": "../../tsconfig.options.json",
"include": [
"src//*",
"types//",
"../../types/**/"
],
"references": [
{
"path": "../visx-group"
},
{
"path": "../visx-vendor"
}
]
}
File: packages/visx-glyph/test/tsconfig.json
{
"compilerOptions": {
"composite": false,
"emitDeclarationOnly": false,
"noEmit": true,
"rootDir": ".",
"types": ["vitest/globals"]
},
"extends": "../../../tsconfig.options.json",
"include": ["/*", "../types//", "../../../types/**/"],
"references": [
{
"path": ".."
}
]
}
File: packages/visx-gradient/Readme.md
@visx/gradient
Inspired by: https://dribbble.com/shots/3380672-Sketch-Gradients-Freebie
Example
import { AreaClosed } from '@visx/shape';
import { GradientPinkBlue } from '@visx/gradient';
const GradientArea = () => {
return (
<svg>
<GradientPinkBlue id="gradient" />
<AreaClosed fill="url('#gradient')" />
</svg>
);
};The Definition Caveat
Like patterns, gradients are "defined." When you render <GradientPinkBlue />, it's rendering a<linearGradient/>
element inside a <def> in the SVG.
It's often better to think of these as variable definitions rather than true DOM elements. When you
use fill="url('#gradient')" you're referencing the gradient's id: gradient.
Make your own!
In addition to the preset linear gradients, you can make any linear or radial gradient like so:
import { LinearGradient, RadialGradient } from '@visx/gradient';
<LinearGradient from="#a18cd1" to="#fbc2eb" />;
<RadialGradient from="#a18cd1" to="#fbc2eb" />;Installation
npm install --save @visx/gradientFile: packages/visx-gradient/package.json
{
"name": "@visx/gradient",
"version": "4.0.0",
"description": "visx gradient",
"sideEffects": false,
"main": "lib/index.js",
"module": "esm/index.js",
"types": "lib/index.d.ts",
"exports": {
".": {
"types": "./lib/index.d.ts",
"import": "./esm/index.js",
"require": "./lib/index.js"
}
},
"files": [
"lib",
"esm"
],
"repository": {
"type": "git",
"url": "git+https://github.com/airbnb/visx.git"
},
"keywords": [
"visx",
"react",
"d3",
"visualizations",
"charts"
],
"author": "@hshoff",
"license": "MIT",
"bugs": {
"url": "https://github.com/airbnb/visx/issues"
},
"homepage": "https://github.com/airbnb/visx#readme",
"peerDependencies": {
"@types/react": "^18.0.0 || ^19.0.0",
"react": "^18.0.0 || ^19.0.0"
},
"publishConfig": {
"access": "public"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
}
File: packages/visx-gradient/tsconfig.json
{
"compilerOptions": {
"declarationDir": "lib",
"outDir": "lib",
"rootDir": "src"
},
"exclude": [
"lib",
"test"
],
"extends": "../../tsconfig.options.json",
"include": [
"src//*",
"types//",
"../../types/**/"
],
"references": []
}
File: packages/visx-gradient/test/tsconfig.json
{
"compilerOptions": {
"composite": false,
"emitDeclarationOnly": false,
"noEmit": true,
"rootDir": ".",
"types": ["vitest/globals"]
},
"extends": "../../../tsconfig.options.json",
"include": ["/*", "../types//", "../../../types/**/"],
"references": [
{
"path": ".."
}
]
}
File: packages/visx-grid/Readme.md
@visx/grid
The @visx/grid package lets you create gridlines for charts. <GridRows /> render horizontally,<GridColumns /> render vertically, or you can use a <Grid /> to get them both at once!
Usage
import { Grid } from '@visx/grid';
// or
// import * as Grid from '@visx/grid';
// <Grid.Grid />
const grid = (
<Grid
xScale={xScale}
yScale={yScale}
width={xMax}
height={yMax}
numTicksRows={numTicksForHeight(height)}
numTicksColumns={numTicksForWidth(width)}
/>
);Installation
npm install --save @visx/gridFile: packages/visx-grid/package.json
{
"name": "@visx/grid",
"version": "4.0.0",
"description": "visx grid",
"sideEffects": false,
"main": "lib/index.js",
"module": "esm/index.js",
"types": "lib/index.d.ts",
"exports": {
".": {
"types": "./lib/index.d.ts",
"import": "./esm/index.js",
"require": "./lib/index.js"
}
},
"files": [
"lib",
"esm"
],
"repository": {
"type": "git",
"url": "git+https://github.com/airbnb/visx.git"
},
"keywords": [
"visx",
"react",
"d3",
"visualizations",
"charts"
],
"author": "@hshoff",
"license": "MIT",
"bugs": {
"url": "https://github.com/airbnb/visx/issues"
},
"homepage": "https://github.com/airbnb/visx#readme",
"peerDependencies": {
"@types/react": "^18.0.0 || ^19.0.0",
"react": "^18.0.0 || ^19.0.0"
},
"dependencies": {
"@visx/curve": "workspace:",
"@visx/group": "workspace:",
"@visx/point": "workspace:",
"@visx/scale": "workspace:",
"@visx/shape": "workspace:*",
"classnames": "^2.3.1"
},
"publishConfig": {
"access": "public"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
},
"devDependencies": {
"@types/react": "^19.0.0"
}
}
File: packages/visx-grid/tsconfig.json
{
"compilerOptions": {
"declarationDir": "lib",
"outDir": "lib",
"rootDir": "src"
},
"exclude": [
"lib",
"test"
],
"extends": "../../tsconfig.options.json",
"include": [
"src//*",
"types//",
"../../types/**/"
],
"references": [
{
"path": "../visx-curve"
},
{
"path": "../visx-group"
},
{
"path": "../visx-point"
},
{
"path": "../visx-scale"
},
{
"path": "../visx-shape"
}
]
}
File: packages/visx-grid/test/tsconfig.json
{
"compilerOptions": {
"composite": false,
"emitDeclarationOnly": false,
"noEmit": true,
"rootDir": ".",
"types": ["vitest/globals"]
},
"extends": "../../../tsconfig.options.json",
"include": ["/*", "../types//", "../../../types/**/"],
"references": [
{
"path": ".."
}
]
}
File: packages/visx-group/Readme.md
@visx/group
<Group /> provides a simplified API for SVG <g /> elements, which are containers for other SVG
objects. You may pass in a top and left margin (instead of transform={translate(...)}) and aclassName.
Installation
npm install --save @visx/groupFile: packages/visx-group/package.json
{
"name": "@visx/group",
"version": "4.0.0",
"description": "visx group",
"sideEffects": false,
"main": "lib/index.js",
"module": "esm/index.js",
"files": [
"lib",
"esm"
],
"types": "lib/index.d.ts",
"exports": {
".": {
"types": "./lib/index.d.ts",
"import": "./esm/index.js",
"require": "./lib/index.js"
}
},
"repository": {
"type": "git",
"url": "git+https://github.com/airbnb/visx.git"
},
"keywords": [
"visx",
"react",
"d3",
"visualizations",
"charts",
"svg"
],
"author": "@hshoff",
"license": "MIT",
"bugs": {
"url": "https://github.com/airbnb/visx/issues"
},
"homepage": "https://github.com/airbnb/visx#readme",
"peerDependencies": {
"@types/react": "^18.0.0 || ^19.0.0",
"react": "^18.0.0 || ^19.0.0"
},
"dependencies": {
"classnames": "^2.3.1"
},
"publishConfig": {
"access": "public"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
}
File: packages/visx-group/tsconfig.json
{
"compilerOptions": {
"declarationDir": "lib",
"outDir": "lib",
"rootDir": "src"
},
"exclude": [
"lib",
"test"
],
"extends": "../../tsconfig.options.json",
"include": [
"src//*",
"types//",
"../../types/**/"
],
"references": []
}
File: packages/visx-group/test/tsconfig.json
{
"compilerOptions": {
"composite": false,
"emitDeclarationOnly": false,
"noEmit": true,
"rootDir": ".",
"types": ["vitest/globals"]
},
"extends": "../../../tsconfig.options.json",
"include": ["/*", "../types//", "../../../types/**/"],
"references": [
{
"path": ".."
}
]
}
File: packages/visx-heatmap/Readme.md
@visx/heatmap
A Heatmap is an arrangement of shapes where the data values are represented as colors.
Example
<HeatmapRect
data={data}
xScale={xScale}
yScale={yScale}
colorScale={colorScale}
opacityScale={opacityScale}
binWidth={bWidth}
binHeight={bWidth}
step={dStep}
gap={0}
/>Heatmaps generally require structure that has this shape:
[
{
bin: 1,
bins: [
{
count: 20,
bin: 23,
},
],
},
];However, you're welcome to use your own structure by defining x, y, z accessors such as:
// Example accessors
const x = (d) => d.myBin;
const y = (d) => d.myBins;
const z = (d) => d.myCount;
// Example scale with an accessors
const xScale = scaleLinear({
range: [0, xMax],
domain: extent(data, x),
});Installation
npm install --save @visx/heatmapFile: packages/visx-heatmap/package.json
{
"name": "@visx/heatmap",
"version": "4.0.0",
"description": "visx heatmap",
"sideEffects": false,
"main": "lib/index.js",
"module": "esm/index.js",
"types": "lib/index.d.ts",
"exports": {
".": {
"types": "./lib/index.d.ts",
"import": "./esm/index.js",
"require": "./lib/index.js"
}
},
"files": [
"lib",
"esm"
],
"repository": {
"type": "git",
"url": "git+https://github.com/airbnb/visx.git"
},
"keywords": [
"visx",
"react",
"d3",
"visualizations",
"charts"
],
"author": "@hshoff",
"license": "MIT",
"bugs": {
"url": "https://github.com/airbnb/visx/issues"
},
"homepage": "https://github.com/airbnb/visx#readme",
"publishConfig": {
"access": "public"
},
"peerDependencies": {
"@types/react": "^18.0.0 || ^19.0.0",
"react": "^18.0.0 || ^19.0.0"
},
"dependencies": {
"@visx/group": "workspace:*",
"classnames": "^2.3.1"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
},
"devDependencies": {
"@types/react": "^19.0.0"
}
}
File: packages/visx-heatmap/tsconfig.json
{
"compilerOptions": {
"declarationDir": "lib",
"outDir": "lib",
"rootDir": "src"
},
"exclude": [
"lib",
"test"
],
"extends": "../../tsconfig.options.json",
"include": [
"src//*",
"types//",
"../../types/**/"
],
"references": [
{
"path": "../visx-group"
}
]
}
File: packages/visx-heatmap/test/tsconfig.json
{
"compilerOptions": {
"composite": false,
"emitDeclarationOnly": false,
"noEmit": true,
"rootDir": ".",
"types": ["vitest/globals"]
},
"extends": "../../../tsconfig.options.json",
"include": ["/*", "../types//", "../../../types/**/"],
"references": [
{
"path": ".."
}
]
}
File: packages/visx-hierarchy/Readme.md
@visx/hierarchy
Many datasets are intrinsically hierarchical. This package contains several react components for
visualizing hierarchical data and largely mirrorsd3-hierarchy.
Many components take the same input hierarchy data root node as defined in as specified in thed3-hierarchy module. For convenience, this package also
exports the d3-hierarchyutility to generate this format.
// equivalent to `import { hierarchy } from 'd3-hierarchy';`
import { hierarchy } from '@visx/hierarchy';
const root = hierarchy({
name: 'root',
children: [
{ name: 'child #1' },
{
name: 'child #2',
children: [{ name: 'grandchild #1' }, { name: 'grandchild #2' }, { name: 'grandchild #3' }],
},
],
});Installation
npm install --save @visx/hierarchyFile: packages/visx-hierarchy/package.json
{
"name": "@visx/hierarchy",
"version": "4.0.0",
"description": "visx tree",
"sideEffects": false,
"main": "lib/index.js",
"module": "esm/index.js",
"types": "lib/index.d.ts",
"exports": {
".": {
"types": "./lib/index.d.ts",
"import": "./esm/index.js",
"require": "./lib/index.js"
}
},
"files": [
"lib",
"esm"
],
"repository": {
"type": "git",
"url": "git+https://github.com/airbnb/visx.git"
},
"keywords": [
"visx",
"d3",
"react",
"visualizations",
"charts"
],
"author": "@hshoff",
"license": "MIT",
"bugs": {
"url": "https://github.com/airbnb/visx/issues"
},
"homepage": "https://github.com/airbnb/visx#readme",
"publishConfig": {
"access": "public"
},
"dependencies": {
"@types/d3-hierarchy": "^1.1.6",
"@visx/group": "workspace:*",
"classnames": "^2.3.1",
"d3-hierarchy": "^1.1.4"
},
"peerDependencies": {
"@types/react": "^18.0.0 || ^19.0.0",
"react": "^18.0.0 || ^19.0.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
},
"devDependencies": {
"@types/react": "^19.0.0"
}
}
File: packages/visx-hierarchy/tsconfig.json
{
"compilerOptions": {
"declarationDir": "lib",
"outDir": "lib",
"rootDir": "src"
},
"exclude": [
"lib",
"test"
],
"extends": "../../tsconfig.options.json",
"include": [
"src//*",
"types//",
"../../types/**/"
],
"references": [
{
"path": "../visx-group"
}
]
}
File: packages/visx-hierarchy/test/tsconfig.json
{
"compilerOptions": {
"composite": false,
"emitDeclarationOnly": false,
"noEmit": true,
"rootDir": ".",
"types": ["vitest/globals"]
},
"extends": "../../../tsconfig.options.json",
"include": ["/*", "../types//", "../../../types/**/"],
"references": [
{
"path": ".."
}
]
}
File: packages/visx-kernel/Readme.md
@visx/kernel
Shared primitives for first-party visx hooks.
@visx/kernel keeps user-input handling consistent across the hooks surface: referential stability,
structural equality, accessor normalization, and shared development warnings live in one package
instead of being reimplemented in each consumer package. It also provides stable id generation for
shared SVG and a11y patterns.
Installation
npm install --save @visx/kernelMotivation
visx hooks are designed around one idea: hooks own the math, users own the render tree. That means
first-party hooks like useScale, useAxis, and usePie all receive the same kinds of user input:
data arrays, accessors, options objects, dimensions, ids, and callbacks.
Without a shared substrate, each package has to answer the same questions independently:
- Does this object-shaped input have the same values as last render?
- Should a string accessor and a simple property function behave the same way?
- How do we keep callback identity stable while reading fresh state?
- How do we warn about dirty data with consistent source tags and structured details?
- How do we generate stable ids for clip paths, gradients, labels, and a11y relationships?
Those are cross-cutting contracts, not chart-specific features. @visx/kernel keeps them small,
audited, and consistent so the hooks surface behaves like one library instead of many similar local
implementations.
Primitive-first design
Kernel is not a chart package. It does not create scales, render axes, lay out marks, or own chart
state. It provides the tiny pieces that make those packages predictable.
- Hooks return ordinary values and refs.
- Pure helpers are safe to import on the server.
- User input is normalized before package-specific work begins.
- Warning payloads share one shape across packages.
- Public helpers are added only when multiple first-party packages need the same behavior.
Most applications should use higher-level visx packages directly. Kernel is mainly for first-party
hooks and advanced users building the same kind of low-level primitives.
Basic usage
Stabilize object-shaped inputs
Use useStructuralMemo when an options object should keep the same reference if its shallow values
are unchanged.
import { useStructuralMemo } from '@visx/kernel';
function ChartFrame({ margin }) {
const stableMargin = useStructuralMemo(
{
top: margin?.top ?? 0,
right: margin?.right ?? 0,
bottom: margin?.bottom ?? 0,
left: margin?.left ?? 0,
},
1,
);
return <g transform={`translate(${stableMargin.left}, ${stableMargin.top})`} />;
}Normalize accessors
Use normalizeAccessor when an API accepts either a string key or a function accessor.
import { normalizeAccessor } from '@visx/kernel';
type Datum = { label: string; value: number };
const getValue = normalizeAccessor<Datum, number>('value');
const value = getValue({ label: 'Q1', value: 42 }, 0, []);Simple property accessors normalize to the same cached function as their string-key equivalent.
const byKey = normalizeAccessor<Datum, number>('value');
const byFunction = normalizeAccessor<Datum, number>((datum) => datum.value);
byKey === byFunction; // trueCompute domains with shared warnings
useDomain normalizes accessors, skips invalid values, stabilizes the returned domain, and emits
structured development warnings for dirty input.
import { useDomain } from '@visx/kernel';
function RevenueChart({ data }) {
const domain = useDomain({
data,
accessor: 'revenue',
type: 'linear',
});
return <span>{domain.join(' - ')}</span>;
}Keep callbacks and ids stable
Use useStableCallback when event handlers need stable identity but fresh closed-over values. UseuseStableId for SVG definitions and a11y relationships that must not remount every render.
import { useLatestRef, useStableCallback, useStableId } from '@visx/kernel';
function InteractiveLayer({ data, onSelect }) {
const dataRef = useLatestRef(data);
const clipId = useStableId('scatter-clip');
const handlePointerMove = useStableCallback((index: number) => {
onSelect(dataRef.current[index]);
});
return (
<svg>
<clipPath id={clipId}>
<rect width={400} height={240} />
</clipPath>
<rect clipPath={`url(#${clipId})`} onPointerMove={() => handlePointerMove(0)} />
</svg>
);
}Build and cache path strings
Use createPath when a package needs a small SVG path builder with shared precision behavior. Pass
the resulting string to toPath2D when drawing the same path on Canvas.
import { createPath, toPath2D } from '@visx/kernel';
const d = createPath(2).moveTo(0, 0).lineTo(12.345, 67.89).closePath().toString();
const path = toPath2D(d);toPath2D(d) returns a real Path2D in browsers. On the server, it returns a minimal object that
stores the path string for cache identity and string inspection; it is not a drawing polyfill.
Format numbers consistently
Use formatNumber when a hook needs a small default formatter without adding a d3-format
dependency.
import { formatNumber } from '@visx/kernel';
const label = formatNumber(1234.56, {
maximumFractionDigits: 1,
minimumFractionDigits: 1,
});Capture warning details
Use setWarnHandler in tests, docs, or integrations that need structured warning payloads.
import { setWarnHandler } from '@visx/kernel';
const restore = setWarnHandler(({ code, details, source }) => {
console.info(source, code, details);
});
try {
renderChartWithDirtyData();
} finally {
restore();
}File: packages/visx-kernel/package.json
{
"name": "@visx/kernel",
"version": "4.0.0",
"description": "visx shared hook primitives",
"sideEffects": false,
"main": "lib/index.js",
"module": "esm/index.js",
"types": "lib/index.d.ts",
"exports": {
".": {
"types": "./lib/index.d.ts",
"import": "./esm/index.js",
"require": "./lib/index.js"
}
},
"files": [
"lib",
"esm"
],
"repository": {
"type": "git",
"url": "git+https://github.com/airbnb/visx.git"
},
"keywords": [
"visx",
"react",
"visualizations",
"charts",
"hooks"
],
"author": "@hshoff",
"license": "MIT",
"bugs": {
"url": "https://github.com/airbnb/visx/issues"
},
"homepage": "https://github.com/airbnb/visx#readme",
"peerDependencies": {
"react": "^18.0.0 || ^19.0.0"
},
"publishConfig": {
"access": "public"
}
}
File: packages/visx-kernel/tsconfig.json
{
"compilerOptions": {
"declarationDir": "lib",
"outDir": "lib",
"rootDir": "src"
},
"exclude": [
"lib",
"test"
],
"extends": "../../tsconfig.options.json",
"include": [
"src//*",
"types//",
"../../types/**/"
],
"references": []
}
File: packages/visx-kernel/test/tsconfig.json
{
"compilerOptions": {
"composite": false,
"emitDeclarationOnly": false,
"noEmit": true,
"rootDir": ".",
"types": ["vitest/globals"]
},
"extends": "../../../tsconfig.options.json",
"include": ["/*", "../types//", "../../../types/**/"],
"references": [
{
"path": ".."
}
]
}
File: packages/visx-kernel/test/tsconfig.typecheck.json
{
"compilerOptions": {
"composite": false,
"emitDeclarationOnly": false,
"noEmit": true,
"skipLibCheck": true,
"types": ["node"]
},
"extends": "../../../tsconfig.options.json",
"files": ["api.typecheck.ts"]
}
File: packages/visx-legend/Readme.md
@visx/legend
Legends associate shapes and colors to data, and are associated with scales.
Example
import { LegendThreshold } from '@visx/legend';
import { scaleThreshold } from '@visx/scale';
const threshold = scaleThreshold({
domain: [0.02, 0.04, 0.06, 0.08, 0.1],
range: ['#f2f0f7', '#dadaeb', '#bcbddc', '#9e9ac8', '#756bb1', '#54278f'],
});
function MyChart() {
return (
<div>
<svg>{/** chart stuff */}</svg>
<LegendThreshold
scale={threshold}
direction="column-reverse"
itemDirection="row-reverse"
labelMargin="0 20px 0 0"
shapeMargin="1px 0 0"
/>
</div>
);
}Installation
npm install --save @visx/legendFile: packages/visx-legend/package.json
{
"name": "@visx/legend",
"version": "4.0.0",
"description": "visx legend",
"sideEffects": false,
"main": "lib/index.js",
"module": "esm/index.js",
"types": "lib/index.d.ts",
"exports": {
".": {
"types": "./lib/index.d.ts",
"import": "./esm/index.js",
"require": "./lib/index.js"
}
},
"files": [
"lib",
"esm"
],
"repository": {
"type": "git",
"url": "git+https://github.com/airbnb/visx.git"
},
"keywords": [
"visx",
"react",
"d3",
"visualizations",
"charts"
],
"author": "@hshoff",
"license": "MIT",
"bugs": {
"url": "https://github.com/airbnb/visx/issues"
},
"homepage": "https://github.com/airbnb/visx#readme",
"peerDependencies": {
"@types/react": "^18.0.0 || ^19.0.0",
"react": "^18.0.0 || ^19.0.0"
},
"publishConfig": {
"access": "public"
},
"dependencies": {
"@visx/group": "workspace:",
"@visx/scale": "workspace:",
"classnames": "^2.3.1"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
},
"devDependencies": {
"@types/react": "^19.0.0"
}
}
File: packages/visx-legend/tsconfig.json
{
"compilerOptions": {
"declarationDir": "lib",
"outDir": "lib",
"rootDir": "src"
},
"exclude": [
"lib",
"test"
],
"extends": "../../tsconfig.options.json",
"include": [
"src//*",
"types//",
"../../types/**/"
],
"references": [
{
"path": "../visx-group"
},
{
"path": "../visx-scale"
}
]
}
File: packages/visx-legend/test/tsconfig.json
{
"compilerOptions": {
"composite": false,
"emitDeclarationOnly": false,
"noEmit": true,
"rootDir": ".",
"types": ["vitest/globals"]
},
"extends": "../../../tsconfig.options.json",
"include": ["/*", "../types//", "../../../types/**/"],
"references": [
{
"path": ".."
}
]
}
File: packages/visx-marker/Readme.md
@visx/marker
Markers are graphical objects attached to a , `<line>`, , or ``
element. MDN <marker>
Installation
npm install --save @visx/markerFile: packages/visx-marker/package.json
{
"name": "@visx/marker",
"version": "4.0.0",
"description": "visx marker",
"sideEffects": false,
"main": "lib/index.js",
"module": "esm/index.js",
"types": "lib/index.d.ts",
"exports": {
".": {
"types": "./lib/index.d.ts",
"import": "./esm/index.js",
"require": "./lib/index.js"
}
},
"files": [
"lib",
"esm"
],
"repository": {
"type": "git",
"url": "git+https://github.com/airbnb/visx.git"
},
"keywords": [
"visx",
"react",
"d3",
"visualizations",
"charts"
],
"author": "@hshoff",
"license": "MIT",
"bugs": {
"url": "https://github.com/airbnb/visx/issues"
},
"homepage": "https://github.com/airbnb/visx#readme",
"dependencies": {
"@visx/group": "workspace:",
"@visx/shape": "workspace:",
"classnames": "^2.3.1"
},
"peerDependencies": {
"@types/react": "^18.0.0 || ^19.0.0",
"react": "^18.0.0 || ^19.0.0"
},
"publishConfig": {
"access": "public"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
},
"devDependencies": {
"@types/react": "^19.0.0"
}
}
File: packages/visx-marker/tsconfig.json
{
"compilerOptions": {
"declarationDir": "lib",
"outDir": "lib",
"rootDir": "src"
},
"exclude": [
"lib",
"test"
],
"extends": "../../tsconfig.options.json",
"include": [
"src//*",
"types//",
"../../types/**/"
],
"references": [
{
"path": "../visx-group"
},
{
"path": "../visx-shape"
}
]
}
File: packages/visx-marker/test/tsconfig.json
{
"compilerOptions": {
"composite": false,
"emitDeclarationOnly": false,
"noEmit": true,
"rootDir": ".",
"types": ["vitest/globals"]
},
"extends": "../../../tsconfig.options.json",
"include": ["/*", "../types//", "../../../types/**/"],
"references": [
{
"path": ".."
}
]
}
File: packages/visx-mock-data/Readme.md
@visx/mock-data
The @visx/mock-data package is here to help you test out your graphs.
Installation
npm install --save @visx/mock-dataGenerators
Generators can create simple generic data for you like this:
import Mock from '@visx/mock-data';
const points = Mock.genRandomNormalPoints();`Mock.genRandomNormalPoints()`
Returns a series of random normal x,y points.
`Mock.getDateValue(n)`
Generates n date values an hour apart from each other starting with the current time.
Mocks
Mock are essentially a bunch of data dumps that you can use like this:
import Mock from '@visx/mock-data';
// or import { cityTemperature } from '@visx/mock-data';
const data = Mock.cityTemperature;`Mock.appleStock`
interface AppleStock {
date: string;
close: number;
}
const appleStock: AppleStock[] = [
{ date: '2007-04-24T07:00:00.000Z', close: 93.24 },
...
];`Mock.bitcoinPrice`
interface BitcoinPrices {
currency: string;
prices: BitcoinPrice[];
}
const bitcoinPrice: BitcoinPrices = {
currency: 'USD',
prices: [
{ price: '2486.69', time: '2017-07-03T00:00:00Z' },
...
]
};`Mock.browserUsage`
const browserUsage: BrowserUsage[] = [
{
date: '2015 Jun 15',
'Google Chrome': '48.09',
'Internet Explorer': '24.14',
Firefox: '18.82',
Safari: '7.46',
'Microsoft Edge': '0.03',
Opera: '1.32',
Mozilla: '0.12',
'Other/Unknown': '0.01',
},
...
];`Mock.cityTemperature`
interface CityTemperature {
date: string;
'New York': string;
'San Francisco': string;
Austin: string;
}
const cityTemperature: CityTemperature[] = [
{
date: '20111001',
'New York': '63.4',
'San Francisco': '62.7',
Austin: '72.2',
},
...
];`Mock.exoplanets`
interface Exoplanets {
name: string;
radius: number;
distance: number | null;
}
const exoplanets: Exoplanets[] = [
{
name: 'Jupiter',
radius: 10.97,
distance: 0,
},
...
];`Mock.groupDateValue`
interface GroupDateValue {
key: string;
value: string;
date: string;
}
const groupDateValue: GroupDateValue[] = [
{ key: 'Group1', value: '37', date: '04/23/12' },
...
];`Mock.lesMiserables`
interface LesMiserablesNode {
id: string;
group: number;
}
interface LesMiserablesLink {
source: string;
target: string;
value: number;
}
interface LesMiserables {
nodes: LesMiserablesNode[];
links: LesMiserablesLink[];
}
const lesMiserables: LesMiserables = {
nodes: [
{ id: 'Myriel', group: 1 },
...
],
links: [
{ source: 'Napoleon', target: 'Myriel', value: 1 },
...
],
};`Mock.letterFrequency`
interface LetterFrequency {
letter: string;
frequency: number;
}
const letterFrequency: LetterFrequency[] = [
{ letter: 'A', frequency: 0.08167 },
...
];`Mock.shakespeare`
interface Shakespeare {
id: string;
parent: string | null;
size: number | null;
}
const shakespeare: Shakespeare[] = [
{
id: 'Shakespeare',
parent: null,
size: 0,
},
...
];Source For Components
`generators/`
`mocks/`
File: packages/visx-mock-data/package.json
{
"name": "@visx/mock-data",
"version": "4.0.0",
"description": "visx mock data",
"sideEffects": false,
"main": "lib/index.js",
"module": "esm/index.js",
"types": "lib/index.d.ts",
"exports": {
".": {
"types": "./lib/index.d.ts",
"import": "./esm/index.js",
"require": "./lib/index.js"
}
},
"files": [
"lib",
"esm"
],
"repository": {
"type": "git",
"url": "git+https://github.com/airbnb/visx.git"
},
"keywords": [
"visx",
"react",
"d3",
"visualizations",
"charts"
],
"author": "@hshoff",
"license": "MIT",
"bugs": {
"url": "https://github.com/airbnb/visx/issues"
},
"homepage": "https://github.com/airbnb/visx#readme",
"publishConfig": {
"access": "public"
},
"dependencies": {
"@types/d3-random": "^2.2.0",
"d3-random": "^2.2.2"
}
}
File: packages/visx-mock-data/tsconfig.json
{
"compilerOptions": {
"declarationDir": "lib",
"outDir": "lib",
"rootDir": "src"
},
"exclude": [
"lib",
"test"
],
"extends": "../../tsconfig.options.json",
"include": [
"src//*",
"types//",
"../../types/**/"
],
"references": []
}
File: packages/visx-mock-data/test/tsconfig.json
{
"compilerOptions": {
"composite": false,
"emitDeclarationOnly": false,
"noEmit": true,
"rootDir": ".",
"types": ["vitest/globals"]
},
"extends": "../../../tsconfig.options.json",
"include": ["/*", "../types//", "../../../types/**/"],
"references": [
{
"path": ".."
}
]
}
File: packages/visx-network/Readme.md
@visx/network
A simple package to visualize a network or graph layout. Does not currently handle network layout.
Example Usage
import { Graph, DefaultLink, DefaultNode } from '@visx/network';
const nodes = [
{ x: 50, y: 20 },
{ x: 200, y: 300 },
{ x: 300, y: 40 },
];
const dataSample = {
nodes,
links: [
{ source: nodes[0], target: nodes[1] },
{ source: nodes[1], target: nodes[2] },
{ source: nodes[2], target: nodes[0] },
],
};
const MyGraph = () => (
<Graph graph={dataSample} linkComponent={DefaultLink} nodeComponent={DefaultNode} />
);Installation
npm install --save @visx/networkFile: packages/visx-network/package.json
{
"name": "@visx/network",
"version": "4.0.0",
"description": "visx network",
"sideEffects": false,
"repository": "https://github.com/airbnb/visx",
"main": "lib/index.js",
"module": "esm/index.js",
"types": "lib/index.d.ts",
"exports": {
".": {
"types": "./lib/index.d.ts",
"import": "./esm/index.js",
"require": "./lib/index.js"
}
},
"files": [
"lib",
"esm"
],
"keywords": [
"visx",
"data",
"visualizations",
"charts"
],
"author": "@andyfang_dz",
"license": "MIT",
"dependencies": {
"@visx/group": "workspace:*",
"classnames": "^2.3.1"
},
"peerDependencies": {
"@types/react": "^18.0.0 || ^19.0.0",
"react": "^18.0.0 || ^19.0.0"
},
"publishConfig": {
"access": "public"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
},
"devDependencies": {
"@types/react": "^19.0.0"
}
}
File: packages/visx-network/tsconfig.json
{
"compilerOptions": {
"declarationDir": "lib",
"outDir": "lib",
"rootDir": "src"
},
"exclude": [
"lib",
"test"
],
"extends": "../../tsconfig.options.json",
"include": [
"src//*",
"types//",
"../../types/**/"
],
"references": [
{
"path": "../visx-group"
}
]
}
File: packages/visx-network/test/tsconfig.json
{
"compilerOptions": {
"composite": false,
"emitDeclarationOnly": false,
"noEmit": true,
"rootDir": ".",
"types": ["vitest/globals"]
},
"extends": "../../../tsconfig.options.json",
"include": ["/*", "../types//", "../../../types/**/"],
"references": [
{
"path": ".."
}
]
}
File: packages/visx-pattern/Readme.md
@visx/pattern
Inspired by: http://riccardoscalco.github.io/textures/
Example
import { AreaClosed } from '@visx/shape';
import { PatternLines } from '@visx/pattern';
const PatternArea = () => {
return (
<svg>
<PatternLines
id="lines"
height={5}
width={5}
stroke={'black'}
strokeWidth={1}
orientation={['diagonal']}
/>
<AreaClosed fill="url('#lines')" />
</svg>
);
};The Definition Caveat
Like gradients, patterns are "defined." When you put down a , it's putting a [](https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial/Patterns) attribute in the
SVG.
It's often better to think of these as variable definitions rather than true DOM elements. When you
use fill="url('#pattern')" you're referencing the pattern's id: pattern.
Pre-Made Patterns
`PatternsCircles`
<PatternCircles id="circles" height={6} width={6} stroke={'black'} strokeWidth={1} />`PatternsHexagons`
<PatternHexagons id="hexagons" height={3} size={8} stroke={'red'} strokeWidth={1} />`PatternsLines`
<PatternLines
id="lines"
height={5}
width={5}
stroke={'black'}
strokeWidth={1}
orientation={['diagonal']}
/>`PatternsWaves`
<PatternWaves id="waves" height={4} width={4} stroke={'blue'} strokeWidth={1} />Installation
npm install --save @visx/patternFile: packages/visx-pattern/package.json
{
"name": "@visx/pattern",
"version": "4.0.0",
"description": "visx pattern",
"sideEffects": false,
"main": "lib/index.js",
"module": "esm/index.js",
"types": "lib/index.d.ts",
"exports": {
".": {
"types": "./lib/index.d.ts",
"import": "./esm/index.js",
"require": "./lib/index.js"
}
},
"files": [
"lib",
"esm"
],
"repository": {
"type": "git",
"url": "git+https://github.com/airbnb/visx.git"
},
"keywords": [
"visx",
"react",
"d3",
"visualization",
"charts"
],
"author": "@hshoff",
"license": "MIT",
"bugs": {
"url": "https://github.com/airbnb/visx/issues"
},
"homepage": "https://github.com/airbnb/visx#readme",
"dependencies": {
"classnames": "^2.3.1"
},
"peerDependencies": {
"@types/react": "^18.0.0 || ^19.0.0",
"react": "^18.0.0 || ^19.0.0"
},
"publishConfig": {
"access": "public"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
}
File: packages/visx-pattern/tsconfig.json
{
"compilerOptions": {
"declarationDir": "lib",
"outDir": "lib",
"rootDir": "src"
},
"exclude": [
"lib",
"test"
],
"extends": "../../tsconfig.options.json",
"include": [
"src//*",
"types//",
"../../types/**/"
],
"references": []
}
File: packages/visx-pattern/test/tsconfig.json
{
"compilerOptions": {
"composite": false,
"emitDeclarationOnly": false,
"noEmit": true,
"rootDir": ".",
"types": ["vitest/globals"]
},
"extends": "../../../tsconfig.options.json",
"include": ["/*", "../types//", "../../../types/**/"],
"references": [
{
"path": ".."
}
]
}
File: packages/visx-point/Readme.md
@visx/point
A simple class to represent an x, y coordinate.
Installation
npm install --save @visx/pointExample Usage
import { Point } from '@visx/point';
const point = new Point({ x: 2, y: 3 });
const { x, y } = point.value(); // Get the coords as an object
const [x, y] = point.toArray(); // or arrayMethods
`point.value()`
Returns an { x, y } object with the x and y coordinates.
`point.toArray()`
Returns the coordinates as an array [x, y].
File: packages/visx-point/package.json
{
"name": "@visx/point",
"version": "4.0.0",
"description": "visx point",
"sideEffects": false,
"main": "lib/index.js",
"module": "esm/index.js",
"types": "lib/index.d.ts",
"exports": {
".": {
"types": "./lib/index.d.ts",
"import": "./esm/index.js",
"require": "./lib/index.js"
}
},
"repository": "https://github.com/airbnb/visx",
"files": [
"lib",
"esm"
],
"keywords": [
"visx",
"data",
"visualizations",
"charts"
],
"author": "@hshoff",
"license": "MIT",
"publishConfig": {
"access": "public"
}
}
File: packages/visx-point/tsconfig.json
{
"compilerOptions": {
"declarationDir": "lib",
"outDir": "lib",
"rootDir": "src"
},
"exclude": [
"lib",
"test"
],
"extends": "../../tsconfig.options.json",
"include": [
"src//*",
"types//",
"../../types/**/"
],
"references": []
}
File: packages/visx-point/test/tsconfig.json
{
"compilerOptions": {
"composite": false,
"emitDeclarationOnly": false,
"noEmit": true,
"rootDir": ".",
"types": ["vitest/globals"]
},
"extends": "../../../tsconfig.options.json",
"include": ["/*", "../types//", "../../../types/**/"],
"references": [
{
"path": ".."
}
]
}
File: packages/visx-react-spring/README.md
@visx/react-spring
Although visx is largely unopinioned on animation, there is value in abstracting the complexity +
boilerplate of building animated visx visualization components. This package requiresreact-spring as a peerDependency (to be compatible with any usage within your app) and exports
all visx components that depend on react-spring.
react-spring provides performant primitives for animating react
components and is our recommended library for making animated charts. In order to minimizereact-spring as a dependency across other visx packages, we've consolidated components which
depend on it here.
Installation
npm install --save react-spring @visx/react-springFile: packages/visx-react-spring/package.json
{
"name": "@visx/react-spring",
"version": "4.0.0",
"description": "visx primitives that rely on react-spring for animation",
"sideEffects": false,
"main": "lib/index.js",
"module": "esm/index.js",
"types": "lib/index.d.ts",
"exports": {
".": {
"types": "./lib/index.d.ts",
"import": "./esm/index.js",
"require": "./lib/index.js"
}
},
"files": [
"lib",
"esm"
],
"repository": {
"type": "git",
"url": "git+https://github.com/airbnb/visx.git"
},
"keywords": [
"visx",
"react",
"d3",
"visualizations",
"charts",
"animation",
"react-spring"
],
"contributors": [
{
"name": "Chris Williams",
"url": "https://github.com/williaster"
}
],
"license": "MIT",
"bugs": {
"url": "https://github.com/airbnb/visx/issues"
},
"homepage": "https://github.com/airbnb/visx#readme",
"publishConfig": {
"access": "public"
},
"peerDependencies": {
"@react-spring/web": "^9.7.5 || ^10.0.0",
"@types/react": "^18.0.0 || ^19.0.0",
"react": "^18.0.0 || ^19.0.0"
},
"dependencies": {
"@visx/axis": "workspace:",
"@visx/grid": "workspace:",
"@visx/scale": "workspace:",
"@visx/text": "workspace:",
"classnames": "^2.3.1"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
},
"devDependencies": {
"@types/react": "^19.0.0"
}
}
File: packages/visx-react-spring/tsconfig.json
{
"compilerOptions": {
"declarationDir": "lib",
"outDir": "lib",
"rootDir": "src"
},
"exclude": [
"lib",
"test"
],
"extends": "../../tsconfig.options.json",
"include": [
"src//*",
"types//",
"../../types/**/"
],
"references": [
{
"path": "../visx-axis"
},
{
"path": "../visx-grid"
},
{
"path": "../visx-scale"
},
{
"path": "../visx-text"
}
]
}
File: packages/visx-react-spring/test/tsconfig.json
{
"compilerOptions": {
"composite": false,
"emitDeclarationOnly": false,
"noEmit": true,
"rootDir": ".",
"types": ["vitest/globals"]
},
"extends": "../../../tsconfig.options.json",
"include": ["/*", "../types//", "../../../types/**/"],
"references": [
{
"path": ".."
}
]
}
File: packages/visx-registry/Readme.md
@visx/registry
Source files and validation scripts for the visx shadcn registry. This package is private and has no
runtime API; it exists to ship drop-in chart components through GitHub registry installs.
Motivation
visx is intentionally low level: primitives take props, compose freely, and stay out of your app's
state model. That is what makes visx useful for unusual charts, custom dashboards, and product
interfaces that do not fit a fixed charting API.
The tradeoff is that teams often need a good starting point before they can customize. A line chart,
bar chart, heatmap chart, or treemap chart usually needs the same surrounding work:
- responsive SVG sizing
- theme token usage
- axis and grid styling
- accessible SVG labels and descriptions
- hidden data table fallbacks
- live region wiring
- installable dependency metadata
That work is valuable, but it is repetitive. @visx/registry packages those starting points as
copyable registry items while keeping the installed output plain React and visx primitives.
Registry-first design
The registry package is distribution infrastructure, not a chart framework.
- Registry items install into user projects as source files.
- Installed charts depend on public visx packages, not
@visx/registry. - Source files live under
registry/charts. - The repository root
registry.jsonis the public GitHub registry entrypoint. - The source registries are committed, but generated
public/ritem JSON is not. - Each chart remains editable after install.
This keeps the installed result compatible with the rest of visx: users can change scales, marks,
themes, accessibility labels, data accessors, and layout directly in their app.
Local development
Add or edit chart source in registry/charts, then update registry.json with the item metadata,
dependencies, source path, and install target.
yarn registry:validateThis validates both the root GitHub registry entrypoint and the package source registry with the
shadcn CLI.
Run the focused registry test suite when changing chart source, metadata, or build scripts:
yarn vitest run --project @visx/registryRun the install smoke when changing public item names, file targets, dependencies, or exported
component names:
yarn registry:smokeThe smoke test installs every registry item into fresh Next and Vite fixtures with the real shadcn
CLI and typechecks the installed source.
Item structure
Each registry item should have a stable install name and a matching component export.
registry/charts/line-chart/line-chart.tsx
components/charts/line-chart.tsx
export function LineChart()Use the -chart suffix for chart item names, source files, targets, and exported components. This
keeps registry install names, file names, and generated import names predictable.
GitHub installs
The public registry entrypoint is the repository root registry.json, which includes this package's
source registry:
registry.json
packages/visx-registry/registry.jsonAfter the registry branch lands on the default branch and the referenced visx packages are
published, items can be installed with the shadcn CLI by GitHub address:
npx shadcn@latest add airbnb/visx/line-chartThe local smoke test builds registry item JSON into a temporary directory only so unpublished branch
changes can still be installed into fresh fixtures.
Accessibility and theming
Registry charts should ship with live accessibility wiring from @visx/a11y and theme token usage
from @visx/theme.
Use showLiveRegion={false} when rendering multiple charts on a page that owns a single shared
announcer. The chart should still render its SVG semantics and hidden data table fallback.
Charts should read theme values through visx theme hooks and CSS-ready variables, rather than
hard-coding light and dark mode branches.
File: packages/visx-registry/package.json
{
"name": "@visx/registry",
"version": "4.0.0",
"private": true,
"description": "visx chart registry source files",
"sideEffects": false,
"scripts": {
"build": "yarn run validate",
"smoke:install": "tsx scripts/smokeInstallRegistryItem.ts",
"test": "vitest run",
"validate": "yarn run validate:root && yarn run validate:source",
"validate:root": "shadcn registry validate registry.json --cwd ../..",
"validate:source": "shadcn registry validate"
},
"repository": {
"type": "git",
"url": "git+https://github.com/airbnb/visx.git"
},
"keywords": [
"visx",
"react",
"visualizations",
"charts",
"registry"
],
"author": "@hshoff",
"license": "MIT",
"bugs": {
"url": "https://github.com/airbnb/visx/issues"
},
"homepage": "https://github.com/airbnb/visx#readme",
"dependencies": {
"@visx/a11y": "workspace:",
"@visx/axis": "workspace:",
"@visx/chart": "workspace:",
"@visx/grid": "workspace:",
"@visx/heatmap": "workspace:",
"@visx/hierarchy": "workspace:",
"@visx/responsive": "workspace:",
"@visx/scale": "workspace:",
"@visx/shape": "workspace:",
"@visx/theme": "workspace:",
"@visx/threshold": "workspace:*",
"react": "^18.0.0 || ^19.0.0"
},
"devDependencies": {
"@types/node": "^22.10.2",
"@types/react": "^19.0.0",
"shadcn": "4.11.0",
"tsx": "^4.19.0",
"typescript": "^5.7.0",
"vitest": "4.1.8"
}
}
File: packages/visx-registry/registry.json
{
"$schema": "https://ui.shadcn.com/schema/registry.json",
"name": "visx",
"homepage": "https://github.com/airbnb/visx",
"items": [
{
"name": "line-chart",
"type": "registry:block",
"title": "Line Chart",
"description": "Themed, responsive, accessible line chart built from visx primitives.",
"dependencies": [
"@visx/a11y",
"@visx/axis",
"@visx/chart",
"@visx/grid",
"@visx/responsive",
"@visx/scale",
"@visx/shape",
"@visx/theme"
],
"registryDependencies": [],
"files": [
{
"path": "registry/charts/line-chart/line-chart.tsx",
"type": "registry:component",
"target": "components/charts/line-chart.tsx"
}
],
"meta": {
"a11y": true,
"client": true,
"ssr": true,
"tier": "core"
}
},
{
"name": "bar-chart",
"type": "registry:block",
"title": "Bar Chart",
"description": "Themed, responsive, accessible bar chart built from visx primitives.",
"dependencies": [
"@visx/a11y",
"@visx/axis",
"@visx/chart",
"@visx/grid",
"@visx/responsive",
"@visx/scale",
"@visx/shape",
"@visx/theme"
],
"registryDependencies": [],
"files": [
{
"path": "registry/charts/bar-chart/bar-chart.tsx",
"type": "registry:component",
"target": "components/charts/bar-chart.tsx"
},
{
"path": "registry/charts/bar-chart/chart-ui.tsx",
"type": "registry:component",
"target": "components/charts/chart-ui.tsx"
}
],
"meta": {
"a11y": true,
"client": true,
"ssr": true,
"tier": "core"
}
},
{
"name": "area-chart",
"type": "registry:block",
"title": "Area Chart",
"description": "Themed, responsive, accessible area chart built from visx primitives.",
"dependencies": [
"@visx/a11y",
"@visx/axis",
"@visx/chart",
"@visx/grid",
"@visx/responsive",
"@visx/scale",
"@visx/shape",
"@visx/theme"
],
"registryDependencies": [],
"files": [
{
"path": "registry/charts/area-chart/area-chart.tsx",
"type": "registry:component",
"target": "components/charts/area-chart.tsx"
}
],
"meta": {
"a11y": true,
"client": true,
"ssr": true,
"tier": "core"
}
},
{
"name": "scatter-chart",
"type": "registry:block",
"title": "Scatter Chart",
"description": "Themed, responsive, accessible scatter chart built from visx primitives.",
"dependencies": [
"@visx/a11y",
"@visx/axis",
"@visx/chart",
"@visx/grid",
"@visx/responsive",
"@visx/scale",
"@visx/shape",
"@visx/theme"
],
"registryDependencies": [],
"files": [
{
"path": "registry/charts/scatter-chart/scatter-chart.tsx",
"type": "registry:component",
"target": "components/charts/scatter-chart.tsx"
}
],
"meta": {
"a11y": true,
"client": true,
"ssr": true,
"tier": "core"
}
},
{
"name": "stacked-bar-chart",
"type": "registry:block",
"title": "Stacked Bar Chart",
"description": "Themed, responsive, accessible stacked bar chart built from visx primitives.",
"dependencies": [
"@visx/a11y",
"@visx/axis",
"@visx/chart",
"@visx/grid",
"@visx/responsive",
"@visx/scale",
"@visx/shape",
"@visx/theme"
],
"registryDependencies": [],
"files": [
{
"path": "registry/charts/stacked-bar-chart/stacked-bar-chart.tsx",
"type": "registry:component",
"target": "components/charts/stacked-bar-chart.tsx"
},
{
"path": "registry/charts/bar-chart/chart-ui.tsx",
"type": "registry:component",
"target": "components/charts/chart-ui.tsx"
}
],
"meta": {
"a11y": true,
"client": true,
"ssr": true,
"tier": "core"
}
},
{
"name": "multi-series-line-chart",
"type": "registry:block",
"title": "Multi-series Line Chart",
"description": "Themed, responsive, accessible multi-series line chart built from visx primitives.",
"dependencies": [
"@visx/a11y",
"@visx/axis",
"@visx/chart",
"@visx/grid",
"@visx/responsive",
"@visx/scale",
"@visx/shape",
"@visx/theme"
],
"registryDependencies": [],
"files": [
{
"path": "registry/charts/multi-series-line-chart/multi-series-line-chart.tsx",
"type": "registry:component",
"target": "components/charts/multi-series-line-chart.tsx"
},
{
"path": "registry/charts/bar-chart/chart-ui.tsx",
"type": "registry:component",
"target": "components/charts/chart-ui.tsx"
}
],
"meta": {
"a11y": true,
"client": true,
"ssr": true,
"tier": "core"
}
},
{
"name": "pie-chart",
"type": "registry:block",
"title": "Pie Chart",
"description": "Themed, responsive, accessible pie chart built from visx primitives.",
"dependencies": [
"@visx/a11y",
"@visx/chart",
"@visx/responsive",
"@visx/shape",
"@visx/theme"
],
"registryDependencies": [],
"files": [
{
"path": "registry/charts/pie-chart/pie-chart.tsx",
"type": "registry:component",
"target": "components/charts/pie-chart.tsx"
}
],
"meta": {
"a11y": true,
"client": true,
"ssr": true,
"tier": "core"
}
},
{
"name": "histogram-chart",
"type": "registry:block",
"title": "Histogram Chart",
"description": "Themed, responsive, accessible histogram chart built from visx primitives.",
"dependencies": [
"@visx/a11y",
"@visx/axis",
"@visx/chart",
"@visx/grid",
"@visx/responsive",
"@visx/scale",
"@visx/shape",
"@visx/theme"
],
"registryDependencies": [],
"files": [
{
"path": "registry/charts/histogram-chart/histogram-chart.tsx",
"type": "registry:component",
"target": "components/charts/histogram-chart.tsx"
}
],
"meta": {
"a11y": true,
"client": true,
"ssr": true,
"tier": "core"
}
},
{
"name": "grouped-bar-chart",
"type": "registry:block",
"title": "Grouped Bar Chart",
"description": "Themed, responsive, accessible grouped bar chart built from visx primitives.",
"dependencies": [
"@visx/a11y",
"@visx/axis",
"@visx/chart",
"@visx/grid",
"@visx/responsive",
"@visx/scale",
"@visx/shape",
"@visx/theme"
],
"registryDependencies": [],
"files": [
{
"path": "registry/charts/grouped-bar-chart/grouped-bar-chart.tsx",
"type": "registry:component",
"target": "components/charts/grouped-bar-chart.tsx"
},
{
"path": "registry/charts/bar-chart/chart-ui.tsx",
"type": "registry:component",
"target": "components/charts/chart-ui.tsx"
}
],
"meta": {
"a11y": true,
"client": true,
"ssr": true,
"tier": "extended"
}
},
{
"name": "horizontal-stacked-bar-chart",
"type": "registry:block",
"title": "Horizontal Stacked Bar Chart",
"description": "Themed, responsive, accessible horizontal stacked bar chart built from visx primitives.",
"dependencies": [
"@visx/a11y",
"@visx/axis",
"@visx/chart",
"@visx/grid",
"@visx/responsive",
"@visx/scale",
"@visx/shape",
"@visx/theme"
],
"registryDependencies": [],
"files": [
{
"path": "registry/charts/horizontal-stacked-bar-chart/horizontal-stacked-bar-chart.tsx",
"type": "registry:component",
"target": "components/charts/horizontal-stacked-bar-chart.tsx"
},
{
"path": "registry/charts/bar-chart/chart-ui.tsx",
"type": "registry:component",
"target": "components/charts/chart-ui.tsx"
}
],
"meta": {
"a11y": true,
"client": true,
"ssr": true,
"tier": "extended"
}
},
{
"name": "stacked-area-chart",
"type": "registry:block",
"title": "Stacked Area Chart",
"description": "Themed, responsive, accessible stacked area chart built from visx primitives.",
"dependencies": [
"@visx/a11y",
"@visx/axis",
"@visx/chart",
"@visx/grid",
"@visx/responsive",
"@visx/scale",
"@visx/shape",
"@visx/theme"
],
"registryDependencies": [],
"files": [
{
"path": "registry/charts/stacked-area-chart/stacked-area-chart.tsx",
"type": "registry:component",
"target": "components/charts/stacked-area-chart.tsx"
},
{
"path": "registry/charts/bar-chart/chart-ui.tsx",
"type": "registry:component",
"target": "components/charts/chart-ui.tsx"
}
],
"meta": {
"a11y": true,
"client": true,
"ssr": true,
"tier": "extended"
}
},
{
"name": "threshold-chart",
"type": "registry:block",
"title": "Threshold Chart",
"description": "Themed, responsive, accessible threshold chart built from visx primitives.",
"dependencies": [
"@visx/a11y",
"@visx/axis",
"@visx/chart",
"@visx/grid",
"@visx/responsive",
"@visx/scale",
"@visx/shape",
"@visx/threshold",
"@visx/theme"
],
"registryDependencies": [],
"files": [
{
"path": "registry/charts/threshold-chart/threshold-chart.tsx",
"type": "registry:component",
"target": "components/charts/threshold-chart.tsx"
},
{
"path": "registry/charts/bar-chart/chart-ui.tsx",
"type": "registry:component",
"target": "components/charts/chart-ui.tsx"
}
],
"meta": {
"a11y": true,
"client": true,
"ssr": true,
"tier": "extended"
}
},
{
"name": "heatmap-chart",
"type": "registry:block",
"title": "Heatmap Chart",
"description": "Themed, responsive, accessible heatmap chart built from visx primitives.",
"dependencies": [
"@visx/a11y",
"@visx/chart",
"@visx/heatmap",
"@visx/responsive",
"@visx/scale",
"@visx/theme"
],
"registryDependencies": [],
"files": [
{
"path": "registry/charts/heatmap-chart/heatmap-chart.tsx",
"type": "registry:component",
"target": "components/charts/heatmap-chart.tsx"
}
],
"meta": {
"a11y": true,
"client": true,
"ssr": true,
"tier": "extended"
}
},
{
"name": "radar-chart",
"type": "registry:block",
"title": "Radar Chart",
"description": "Themed, responsive, accessible radar chart built from visx primitives.",
"dependencies": [
"@visx/a11y",
"@visx/chart",
"@visx/responsive",
"@visx/scale",
"@visx/theme"
],
"registryDependencies": [],
"files": [
{
"path": "registry/charts/radar-chart/radar-chart.tsx",
"type": "registry:component",
"target": "components/charts/radar-chart.tsx"
}
],
"meta": {
"a11y": true,
"client": true,
"ssr": true,
"tier": "extended"
}
},
{
"name": "radial-bar-chart",
"type": "registry:block",
"title": "Radial Bar Chart",
"description": "Themed, responsive, accessible radial bar chart built from visx primitives.",
"dependencies": [
"@visx/a11y",
"@visx/chart",
"@visx/responsive",
"@visx/scale",
"@visx/shape",
"@visx/theme"
],
"registryDependencies": [],
"files": [
{
"path": "registry/charts/radial-bar-chart/radial-bar-chart.tsx",
"type": "registry:component",
"target": "components/charts/radial-bar-chart.tsx"
}
],
"meta": {
"a11y": true,
"client": true,
"ssr": true,
"tier": "extended"
}
},
{
"name": "treemap-chart",
"type": "registry:block",
"title": "Treemap Chart",
"description": "Themed, responsive, accessible treemap chart built from visx primitives.",
"dependencies": [
"@visx/a11y",
"@visx/chart",
"@visx/hierarchy",
"@visx/responsive",
"@visx/scale",
"@visx/theme"
],
"registryDependencies": [],
"files": [
{
"path": "registry/charts/treemap-chart/treemap-chart.tsx",
"type": "registry:component",
"target": "components/charts/treemap-chart.tsx"
}
],
"meta": {
"a11y": true,
"client": true,
"ssr": true,
"tier": "extended"
}
}
]
}
File: packages/visx-registry/tsconfig.json
{
"compilerOptions": {
"declarationDir": "lib",
"outDir": "lib",
"rootDir": "src"
},
"exclude": [
"lib",
"public",
"registry",
"scripts",
"test"
],
"extends": "../../tsconfig.options.json",
"include": [
"src//*",
"types//",
"../../types/**/"
],
"references": [
{
"path": "../visx-a11y"
},
{
"path": "../visx-axis"
},
{
"path": "../visx-chart"
},
{
"path": "../visx-grid"
},
{
"path": "../visx-heatmap"
},
{
"path": "../visx-hierarchy"
},
{
"path": "../visx-responsive"
},
{
"path": "../visx-scale"
},
{
"path": "../visx-shape"
},
{
"path": "../visx-theme"
},
{
"path": "../visx-threshold"
}
]
}
File: packages/visx-responsive/Readme.md
@visx/responsive
The @visx/responsive package is here to help you make responsive graphs by providing a collection
of hooks, enhancers and components.
Installation
npm install --save @visx/responsiveHooks
`useScreenSize`
If you would like your graph to adapt to the screen size, you can use the useScreenSize() hook. It
returns current screen width and height and updates the value automatically on browser window
resize. You can optionally pass a config object as an argument to the hook. Config object attributes
are:
initialSize- initial size before measuring the screen, defaults to{ width: 0, height: 0 }.debounceTime- determines how often the size is updated in milliseconds, defaults to300.enableDebounceLeadingCall- determines whether the size is updated immediately on first render,
defaults totrue. This is essentially the value ofoptions.leadingin Lodash'sdebounce.
Example
import { useScreenSize } from '@visx/responsive';
const ChartToRender = () => {
const { width, height } = useScreenSize({ debounceTime: 150 });
return (
<svg width={width} height={height}>
{/* content */}
</svg>
);
};
const chartToRender = <ChartToRender myProp="string" />;`useParentSize`
If you want your graph to adapt to its parent size, you can use useParentSize() hook.
`` uses this hook internally. The hook returns width, height, left, top
properties which describe dimensions of the container which received parentRef ref. You can
optionally pass a config object as an argument to the hook. Config object attributes are:
initialSize- initial size before measuring the parent, defaults to{ width: 0, height: 0, left: 0, top: 0 }.debounceTime- determines how often the size is updated in miliseconds, defaults to300.enableDebounceLeadingCall- determines whether the size is updated immediately on first render,
defaults totrue. This is essentially the value ofoptions.leadingin Lodash'sdebounce.ignoreDimensions- array of dimensions for which an update should be skipped. For example, if
you pass['width'], width changes of the component that receivedparentRefwon't be
propagated. Defaults to[](all dimensions changes trigger updates).
Example
import { useParentSize } from '@visx/responsive';
const ChartToRender = () => {
const { parentRef, width, height } = useParentSize({ debounceTime: 150 });
return (
<div ref={parentRef}>
<svg width={width} height={height}>
{/* content */}
</svg>
</div>
);
};
const chartToRender = <ChartToRender myProp="string" />;Enhancers / (HOCs)
`withScreenSize`
If you prefer to use an enhancer, you can use the withScreenSize(). The resulting component will
pass screenWidth and screenHeight props to the wrapped component containing the respective
screen dimensions. You can also optionally pass config props to the wrapped component:
debounceTime- determines how often the size is updated in milliseconds, defaults to300.windowResizeDebounceTime- deprecated, equivalent to the above, kept for backwards compatibilityenableDebounceLeadingCall- determines whether the size is updated immediately on first render,
defaults totrue. This is essentially the value ofoptions.leadingin Lodash'sdebounce.
Example
import { withScreenSize, WithScreenSizeProvidedProps } from '@visx/responsive';
interface Props extends WithScreenSizeProvidedProps {
myProp: string;
}
const MySuperCoolVisxChart = ({ myProp, screenWidth, screenHeight }: Props) => {
// ...
};
const ChartToRender = withScreenSize(MySuperCoolVisxChart);
const chartToRender = <ChartToRender myProp="string" />;`withParentSize`
If you prefer to use an enhancer to adapt your graph to its parent component's size, you can usewithParentSize(). The resulting component will pass parentWidth and parentHeight props to the
wrapped component containing the respective parent's dimensions. You can also optionally pass config
props to the wrapped component:
initialWidth- initial chart width used before the parent size is determined.initialHeight- initial chart height used before the parent size is determined.debounceTime- determines how often the size is updated in miliseconds, defaults to300.enableDebounceLeadingCall- determines whether the size is updated immediately on first render,
defaults totrue. This is essentially the value ofoptions.leadingin Lodash'sdebounce.
Example
import { withParentSize, WithParentSizeProvidedProps } from '@visx/responsive';
interface Props extends WithParentSizeProvidedProps {
myProp: string;
}
const MySuperCoolVisxChart = ({ myProp, parentWidth, parentHeight }: Props) => {
// ...
};
const ChartWithParentSize = withParentSize(MySuperCoolVisxChart);
const chartToRender = <ChartWithParentSize myProp="string" initialWidth={400} />;Components
`ParentSize`
You might do the same thing as useParentSize or withParentSize using the ParentSize component.
Example
import { ParentSize } from '@visx/responsive';
const chartToRender = (
<ParentSize>
{(parent) => (
<MySuperCoolVisxChart
parentWidth={parent.width}
parentHeight={parent.height}
parentTop={parent.top}
parentLeft={parent.left}
// this is the referrer to the wrapper component
parentRef={parent.ref}
// this function can be called inside MyVisxChart to cause a resize of the wrapper component
resizeParent={parent.resize}
/>
)}
</ParentSize>
);`ScaleSVG`
You can also create a responsive chart with a specific viewBox with the ScaleSVG component.
Example
import { ScaleSVG } from '@visx/responsive';
const chartToRender = (
<ScaleSVG width={400} height={400}>
<MySuperCoolVXChart />
</ScaleSVG>
);⚠️ `ResizeObserver` dependency
useParentSize, ParentSize and withParentSize rely on ResizeObservers for auto-sizing. If you
need a polyfill, you can either pollute the window object or inject it cleanly like this:
import { ResizeObserver } from 'your-favorite-polyfill';
// hook
useParentSize({ resizeObserverPolyfill: ResizeObserver });
// component
<ParentSize resizeObserverPolyfill={ResizeObserver} {...}>
{() => {...}}
</ParentSize>
// enhancer
withParentSize(MyComponent, ResizeObserver);File: packages/visx-responsive/package.json
{
"name": "@visx/responsive",
"version": "4.0.0",
"description": "visx responsive svg",
"sideEffects": false,
"main": "lib/index.js",
"module": "esm/index.js",
"types": "lib/index.d.ts",
"exports": {
".": {
"types": "./lib/index.d.ts",
"import": "./esm/index.js",
"require": "./lib/index.js"
}
},
"files": [
"lib",
"esm"
],
"repository": {
"type": "git",
"url": "git+https://github.com/airbnb/visx.git"
},
"keywords": [
"visx",
"react",
"d3",
"visualizations",
"charts"
],
"author": "@hshoff",
"license": "MIT",
"bugs": {
"url": "https://github.com/airbnb/visx/issues"
},
"homepage": "https://github.com/airbnb/visx#readme",
"peerDependencies": {
"@types/react": "^18.0.0 || ^19.0.0",
"react": "^18.0.0 || ^19.0.0"
},
"devDependencies": {
"@juggle/resize-observer": "^3.3.1"
},
"publishConfig": {
"access": "public"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
}
File: packages/visx-responsive/tsconfig.json
{
"compilerOptions": {
"declarationDir": "lib",
"outDir": "lib",
"rootDir": "src"
},
"exclude": [
"lib",
"test"
],
"extends": "../../tsconfig.options.json",
"include": [
"src//*",
"types//",
"../../types/**/"
],
"references": []
}
File: packages/visx-responsive/test/tsconfig.json
{
"compilerOptions": {
"composite": false,
"emitDeclarationOnly": false,
"noEmit": true,
"rootDir": ".",
"types": ["vitest/globals"]
},
"extends": "../../../tsconfig.options.json",
"include": ["/*", "../types//", "../../../types/**/"],
"references": [
{
"path": ".."
}
]
}
File: packages/visx-sankey/Readme.md
@visx/sankey
Sankey diagrams visualize the directed flow between nodes in an acyclic network. This package
contains react components for visualizing sankey diagrams and largely mirrorsd3-sankey.
Many components take the same input sankey data as defined in as specified in thed3-sankey module to output a graph of the sankey layout. For
convenience, this package also exports the d3-sankeyutility to
generate this format.
Installation
npm install --save @visx/sankeyUsage
The @visx/sankey package exports a wrapped version of d3-sankey for flexible usage, as well as a<Sankey /> component for rendering the sankey layout.
// equivalent to `import { sankey } from 'd3-sankey';`
import { sankey } from '@visx/sankey';
const generator = sankey();
const graph = generator({
nodes: [{ name: 'node 1' }, { name: 'node 2' }, { name: 'node 3' }],
links: [
{ source: 0, target: 1, value: 10 },
{ source: 1, target: 2, value: 5 },
],
});import { Sankey, sankeyCenter } from '@visx/sankey';
const nodes = [{ name: 'node 1' }, { name: 'node 2' }, { name: 'node 3' }];
const links = [
{ source: 0, target: 1, value: 10 },
{ source: 1, target: 2, value: 5 },
];
const data = { nodes, links };
return (
<svg>
<Sankey root={data} nodeAlign={sankeyCenter} size={[100, 100]} />
</svg>
);The layout output can also be customized by providing a children function to the <Sankey />
component.
import { Sankey, sankeyCenter } from '@visx/sankey';
import { Group } from '@visx/group';
import { BarRounded, LinkHorizontal } from '@visx/group';
const nodes = [{ name: 'node 1' }, { name: 'node 2' }, { name: 'node 3' }];
const links = [
{ source: 0, target: 1, value: 10 },
{ source: 1, target: 2, value: 5 },
];
const data = { nodes, links };
return (
<svg>
<Sankey root={data} nodeAlign={sankeyCenter} size={[100, 100]}>
{({ graph, createPath }) => (
<>
<Group>
{graph.links.map((link, i) => (
<LinkHorizontal
key={i}
data={link}
path={createPath}
fill="transparent"
stroke="#f50057"
strokeWidth={link.width}
strokeOpacity={0.5}
/>
))}
</Group>
<Group>
{graph.nodes.map(({ y0, y1, x0, x1, name }, i) => (
<BarRounded
key={i}
width={x1 - x0}
height={y1 - y0}
x={x0}
y={y0}
radius={3}
fill="#f50057"
all
/>
))}
</Group>
</>
)}
</Sankey>
</svg>
);File: packages/visx-sankey/package.json
{
"name": "@visx/sankey",
"version": "4.0.0",
"description": "visx sankey",
"sideEffects": false,
"main": "lib/index.js",
"module": "esm/index.js",
"types": "lib/index.d.ts",
"exports": {
".": {
"types": "./lib/index.d.ts",
"import": "./esm/index.js",
"require": "./lib/index.js"
}
},
"files": [
"lib",
"esm"
],
"repository": {
"type": "git",
"url": "git+https://github.com/airbnb/visx.git"
},
"keywords": [
"visx",
"d3",
"react",
"visualizations",
"charts"
],
"author": "@jacksonhardaker",
"license": "MIT",
"bugs": {
"url": "https://github.com/airbnb/visx/issues"
},
"homepage": "https://github.com/airbnb/visx#readme",
"publishConfig": {
"access": "public"
},
"dependencies": {
"@types/d3-sankey": "^0.12.4",
"@visx/group": "workspace:",
"@visx/vendor": "workspace:",
"classnames": "^2.3.1",
"d3-sankey": "^0.12.3"
},
"peerDependencies": {
"@types/react": "^18.0.0 || ^19.0.0",
"react": "^18.0.0 || ^19.0.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
},
"devDependencies": {
"@types/react": "^19.0.0"
}
}
File: packages/visx-sankey/tsconfig.json
{
"compilerOptions": {
"declarationDir": "lib",
"outDir": "lib",
"rootDir": "src"
},
"exclude": [
"lib",
"test"
],
"extends": "../../tsconfig.options.json",
"include": [
"src//*",
"types//",
"../../types/**/"
],
"references": [
{
"path": "../visx-group"
},
{
"path": "../visx-vendor"
}
]
}
File: packages/visx-scale/Readme.md
@visx/scale
Installation
npm install --save @visx/scaleOverview of scales
The @visx/scale package aims to provide a wrapper around existing d3 scaling originally defined
in the d3-scale package.
Scales are functions that help you map your data values to the physical pixel size that your graph
requires. For example, let's say you wanted to create a bar chart to show populations per country.
If you were to use a 1-to-1 scale (IE: 1 pixel per y value) your bar for the USA would be about
321.4 million pixels high!
Instead, you can tell visx a function to use that takes a data value (like your population per
country) and quantitatively maps to another dimensional space, like pixels.
For example, we could create a linear scale like this:
const graphWidth = 500;
const graphHeight = 200;
const [minX, maxX] = getXMinAndMax();
const [minY, maxY] = getYMinAndMax();
const xScale = Scale.scaleLinear({
domain: [minX, maxX], // x-coordinate data values
range: [0, graphWidth], // svg x-coordinates, svg x-coordinates increase left to right
round: true,
});
const yScale = Scale.scaleLinear({
domain: [minY, maxY], // y-coordinate data values
// svg y-coordinates, these increase from top to bottom so we reverse the order
// so that minY in data space maps to graphHeight in svg y-coordinate space
range: [graphHeight, 0],
round: true,
});
// ...
const points = data.map((d, i) => {
const barHeight = graphHeight - yScale(d.y);
return <Shape.Bar height={barHeight} y={graphHeight - barHeight} />;
});Different types of scales
Band scale
Example:
const scale = Scale.scaleBand({
/*
range,
round,
domain,
padding,
nice = false
*/
});Linear scale
Example:
const scale = Scale.scaleLinear({
/*
range,
round,
domain,
nice = false,
clamp = false,
*/
});Log scale
Example:
const scale = Scale.scaleLog({
/*
range,
round,
domain,
base,
nice = false,
clamp = false,
*/
});Important note: As log(0) = -∞, a log scale domain must be strictly-positive or
strictly-negative; the domain must not include or cross zero.
Radial scale
Example:
const scale = Scale.scaleRadial({
/*
range,
round,
domain,
nice = false,
clamp = false,
*/
});Ordinal scale
Example:
const scale = Scale.scaleOrdinal({
/*
range,
domain,
unknown,
*/
});Point scale
Example:
const scale = Scale.scalePoint({
/*
range,
round,
domain,
padding,
align,
nice = false,
*/
});Power scale
Example:
const scale = Scale.scalePower({
/*
range,
round,
domain,
exponent,
nice = false,
clamp = false,
*/
});Square Root scale
Example:
// No need to set the exponent, It is always 0.5
const scale = Scale.scaleSqrt({
/*
range,
round,
domain,
nice = false,
clamp = false,
*/
});Time scale
Example:
const scale = Scale.scaleTime({
/*
range,
round,
domain,
nice = false,
clamp = false,
*/
});You also can scale time with Coordinated Universal Time via scaleUtc.
Example:
const scale = Scale.scaleUtc({
/*
range,
round,
domain,
nice = false,
clamp = false,
*/
});Color Scales
D3 scales offer the ability to map points to colors. You can used3-scale-chromatic in conjunction with visx'sscaleOrdinal to make color scales.
You can install d3-scale-chromatic with npm:
npm install --save d3-scale-chromaticYou create a color scale like so:
import { scaleOrdinal } from '@visx/scale';
import { schemeSet1 } from 'd3-scale-chromatic';
const colorScale = scaleOrdinal({
domain: arrayOfThings,
range: schemeSet1,
});This generates a color scale with the following colors:
There are a number of other
categorical color schemes
available, along with other continuous color schemes.
File: packages/visx-scale/package.json
{
"name": "@visx/scale",
"version": "4.0.0",
"description": "visx scale",
"sideEffects": false,
"main": "lib/index.js",
"module": "esm/index.js",
"types": "lib/index.d.ts",
"exports": {
".": {
"types": "./lib/index.d.ts",
"import": "./esm/index.js",
"require": "./lib/index.js"
},
"./react": {
"types": "./lib/react/index.d.ts",
"import": "./esm/react/index.js",
"require": "./lib/react/index.js"
}
},
"files": [
"lib",
"esm"
],
"repository": {
"type": "git",
"url": "git+https://github.com/airbnb/visx.git"
},
"keywords": [
"visx",
"react",
"d3",
"visualizations",
"charts"
],
"authors": [
"@hshoff",
"@kristw"
],
"license": "MIT",
"bugs": {
"url": "https://github.com/airbnb/visx/issues"
},
"homepage": "https://github.com/airbnb/visx#readme",
"dependencies": {
"@visx/vendor": "workspace:*"
},
"peerDependencies": {
"@types/react": "^18.0.0 || ^19.0.0",
"react": "^18.0.0 || ^19.0.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"react": {
"optional": true
}
},
"devDependencies": {
"@types/react": "^19.0.0"
},
"publishConfig": {
"access": "public"
}
}
File: packages/visx-scale/tsconfig.json
{
"compilerOptions": {
"declarationDir": "lib",
"outDir": "lib",
"rootDir": "src"
},
"exclude": [
"lib",
"test"
],
"extends": "../../tsconfig.options.json",
"include": [
"src//*",
"types//",
"../../types/**/"
],
"references": [
{
"path": "../visx-vendor"
}
]
}
File: packages/visx-scale/test/tsconfig.json
{
"compilerOptions": {
"composite": false,
"emitDeclarationOnly": false,
"noEmit": true,
"rootDir": ".",
"types": ["vitest/globals"]
},
"extends": "../../../tsconfig.options.json",
"include": ["/*", "../types//", "../../../types/**/"],
"references": [
{
"path": ".."
}
]
}
File: packages/visx-shape/Readme.md
@visx/shape
Shapes are the core elements of visx. Most of what you see on the screen, like lines, bars, and
areas are all made with shape primitives.
Installation
npm install --save @visx/shapeFile: packages/visx-shape/package.json
{
"name": "@visx/shape",
"version": "4.0.0",
"description": "visx shape",
"sideEffects": false,
"main": "lib/index.js",
"module": "esm/index.js",
"types": "lib/index.d.ts",
"exports": {
".": {
"types": "./lib/index.d.ts",
"import": "./esm/index.js",
"require": "./lib/index.js"
},
"./react": {
"types": "./lib/react/index.d.ts",
"import": "./esm/react/index.js",
"require": "./lib/react/index.js"
}
},
"repository": "https://github.com/airbnb/visx",
"files": [
"lib",
"esm"
],
"keywords": [
"visx",
"react",
"d3",
"visualizations",
"charts"
],
"author": "@hshoff",
"license": "MIT",
"dependencies": {
"@visx/curve": "workspace:",
"@visx/group": "workspace:",
"@visx/scale": "workspace:",
"@visx/vendor": "workspace:",
"classnames": "^2.3.1"
},
"peerDependencies": {
"@types/react": "^18.0.0 || ^19.0.0",
"react": "^18.0.0 || ^19.0.0"
},
"publishConfig": {
"access": "public"
},
"devDependencies": {
"@types/d3-hierarchy": "^1.1.6",
"@types/react": "^19.0.0",
"d3-hierarchy": "^1.1.8"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
}
File: packages/visx-shape/tsconfig.json
{
"compilerOptions": {
"declarationDir": "lib",
"outDir": "lib",
"rootDir": "src"
},
"exclude": [
"lib",
"test"
],
"extends": "../../tsconfig.options.json",
"include": [
"src//*",
"types//",
"../../types/**/"
],
"references": [
{
"path": "../visx-curve"
},
{
"path": "../visx-group"
},
{
"path": "../visx-scale"
},
{
"path": "../visx-vendor"
}
]
}
File: packages/visx-shape/test/tsconfig.json
{
"compilerOptions": {
"composite": false,
"emitDeclarationOnly": false,
"noEmit": true,
"rootDir": ".",
"types": ["vitest/globals"]
},
"extends": "../../../tsconfig.options.json",
"include": ["/*", "../types//", "../../../types/**/"],
"references": [
{
"path": ".."
}
]
}
File: packages/visx-stats/Readme.md
@visx/stats
The package provides react components for visualizing distributions, such as Box Plots and Violin
Plots
Installation
npm install --save @visx/statsFile: packages/visx-stats/package.json
{
"name": "@visx/stats",
"version": "4.0.0",
"description": "visx stats box violin",
"sideEffects": false,
"main": "lib/index.js",
"module": "esm/index.js",
"types": "lib/index.d.ts",
"exports": {
".": {
"types": "./lib/index.d.ts",
"import": "./esm/index.js",
"require": "./lib/index.js"
}
},
"files": [
"lib",
"esm"
],
"repository": {
"type": "git",
"url": "git+https://github.com/airbnb/visx.git"
},
"keywords": [
"visx",
"react",
"d3",
"visualizations",
"charts"
],
"author": "@conglei",
"license": "MIT",
"bugs": {
"url": "https://github.com/airbnb/visx/issues"
},
"homepage": "https://github.com/airbnb/visx#readme",
"dependencies": {
"@visx/group": "workspace:",
"@visx/scale": "workspace:",
"@visx/vendor": "workspace:*",
"classnames": "^2.3.1"
},
"peerDependencies": {
"@types/react": "^18.0.0 || ^19.0.0",
"react": "^18.0.0 || ^19.0.0"
},
"publishConfig": {
"access": "public"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
},
"devDependencies": {
"@types/react": "^19.0.0"
}
}
File: packages/visx-stats/tsconfig.json
{
"compilerOptions": {
"declarationDir": "lib",
"outDir": "lib",
"rootDir": "src"
},
"exclude": [
"lib",
"test"
],
"extends": "../../tsconfig.options.json",
"include": [
"src//*",
"types//",
"../../types/**/"
],
"references": [
{
"path": "../visx-group"
},
{
"path": "../visx-scale"
},
{
"path": "../visx-vendor"
}
]
}
File: packages/visx-stats/test/tsconfig.json
{
"compilerOptions": {
"composite": false,
"emitDeclarationOnly": false,
"noEmit": true,
"rootDir": ".",
"types": ["vitest/globals"]
},
"extends": "../../../tsconfig.options.json",
"include": ["/*", "../types//", "../../../types/**/"],
"references": [
{
"path": ".."
}
]
}
File: packages/visx-text/Readme.md
@visx/text
The @visx/text provides a better SVG <Text> component with the following features
- Word-wrapping (when
widthprop is defined) - Vertical alignment (
verticalAnchorprop) - Rotation (
angleprop) - Scale-to-fit text (
scaleToFitprop)
Example
Simple demo to show off a useful feature. Since svg <text> itself does not supportverticalAnchor, normally text rendered at 0,0 would be outside the viewport and thus not
visible. By using <Text> with the verticalAnchor="start" prop, the text will now be visible as
you'd expect.
import React from 'react';
// note: react@18 syntax
import { createRoot } from 'react-dom/client';
import { Text } from '@visx/text';
const App = () => (
<svg>
<Text verticalAnchor="start">Hello world</Text>
</svg>
);
const root = createRoot(document.getElementById('root'));
root.render(<App />);Installation
npm install --save @visx/textFile: packages/visx-text/package.json
{
"name": "@visx/text",
"version": "4.0.0",
"description": "visx text",
"sideEffects": false,
"main": "lib/index.js",
"module": "esm/index.js",
"types": "lib/index.d.ts",
"exports": {
".": {
"types": "./lib/index.d.ts",
"import": "./esm/index.js",
"require": "./lib/index.js"
}
},
"files": [
"lib",
"esm"
],
"repository": {
"type": "git",
"url": "git+https://github.com/airbnb/visx.git"
},
"keywords": [
"visx",
"react",
"d3",
"visualization",
"chart"
],
"author": "@techniq",
"license": "MIT",
"bugs": {
"url": "https://github.com/airbnb/visx/issues"
},
"homepage": "https://github.com/airbnb/visx#readme",
"dependencies": {
"classnames": "^2.3.1",
"reduce-css-calc": "^1.3.0"
},
"peerDependencies": {
"@types/react": "^18.0.0 || ^19.0.0",
"react": "^18.0.0 || ^19.0.0"
},
"publishConfig": {
"access": "public"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
}
File: packages/visx-text/tsconfig.json
{
"compilerOptions": {
"declarationDir": "lib",
"outDir": "lib",
"rootDir": "src"
},
"exclude": [
"lib",
"test"
],
"extends": "../../tsconfig.options.json",
"include": [
"src//*",
"types//",
"../../types/**/"
],
"references": []
}
File: packages/visx-text/test/tsconfig.json
{
"compilerOptions": {
"composite": false,
"emitDeclarationOnly": false,
"noEmit": true,
"rootDir": ".",
"types": ["vitest/globals"]
},
"extends": "../../../tsconfig.options.json",
"include": ["/*", "../types//", "../../../types/**/"],
"references": [
{
"path": ".."
}
]
}
File: packages/visx-theme/Readme.md
@visx/theme
Utilities for sharing visual tokens across visx charts without changing the low-level visx primitive
model. The package is split into an RSC-safe root entry for CSS scoping and a client entry for React
hooks.
Installation
npm install --save @visx/themeMotivation
visx is intentionally low level: primitives take props, compose freely, and stay out of your app's
state model. That is what makes visx useful for unusual charts, custom dashboards, and product
interfaces that do not fit a fixed charting API.
The tradeoff is that every primitive chart tends to rebuild the same styling layer:
- categorical colors for each series
- axis strokes, tick labels, and grid lines
- text colors, font family, and chart surfaces
- light/dark color branches
- design-system token plumbing
That works for one chart. It gets noisy when a dashboard has many charts built from different visx
packages. Small differences creep in, dark mode becomes duplicated JavaScript, and teams end up
copying local helpers from chart to chart.
@visx/theme gives those charts a shared visual language while keeping the rendering primitives
plain. It does not make @visx/axis, @visx/grid, or @visx/shape theme-aware. Instead, it gives
you CSS-ready values and small prop helpers that you can pass to the primitives you already use.
Primitive-first design
The theme package is a convenience layer, not a chart framework.
- visx primitives remain prop-driven.
- Theme hooks return ordinary strings, numbers, and prop objects.
- CSS owns resolved colors through custom properties.
- Explicit chart props and
ChartConfig.coloroverrides always win. - Apps own light/dark mode, class names, data attributes, and design-system providers.
- You can use one hook, the whole provider, or only
ThemeScope.
This keeps shadcn/ui integration zero-config for common apps without making shadcn/ui a requirement
or a constraint. If a chart needs a custom palette, a per-series CSS variable, a hand-tuned axis, or
no theme integration at all, the primitive API still supports that.
Basic usage
Use ThemeScope from the root entry when a server component or app layout only needs to provide the
chart CSS variable boundary.
import { ThemeScope } from '@visx/theme';
import type { ReactNode } from 'react';
export default function DashboardLayout({ children }: { children: ReactNode }) {
return (
<ThemeScope theme="auto" className="dashboard-charts">
{children}
</ThemeScope>
);
}Use ThemeProvider from the client entry when chart components need theme hooks.
'use client';
import { ThemeProvider } from '@visx/theme/react';
import type { ReactNode } from 'react';
export function ChartShell({ children }: { children: ReactNode }) {
return <ThemeProvider theme="auto">{children}</ThemeProvider>;
}theme="auto" does not emit generated variables. It returns CSS-ready var(...) values, so the app
can own the current light or dark mode through classes, data attributes, media queries, or inline
CSS variables.
shadcn/ui variables
The default auto theme reads the same chart variable names commonly used by shadcn/ui:
.light {
--chart-1: #2563eb;
--chart-2: #16a34a;
--background: #ffffff;
--card: #ffffff;
--border: #e5e7eb;
--foreground: #0f172a;
--muted-foreground: #64748b;
}
.dark {
--chart-1: #60a5fa;
--chart-2: #4ade80;
--background: #020617;
--card: #0f172a;
--border: #334155;
--foreground: #f8fafc;
--muted-foreground: #94a3b8;
}When the surrounding app flips .light to .dark, CSS variables update the chart colors.@visx/theme does not install a mode switcher, call matchMedia, or read the DOM.
Auto-mode limitation
CSS-backed tokens update through variables in auto mode:
- colors
- categorical colors
- background, surface, border, and text colors
- font family
JS-only numeric values cannot update from CSS alone:
- chart margins
- axis stroke width and tick length
- grid stroke width
- font sizes
Auto mode uses the light theme numeric defaults for those JS-only values. Pass an explicit theme
object from defineTheme when light and dark modes need different layout measurements.
Migrating from `@visx/xychart`
Existing xychart code can keep using XYChartTheme directly. New primitive charts can reuse the
same visual choices with fromXYChartTheme.
import { XYChart, buildChartTheme } from '@visx/xychart';
import { ThemeScope, fromXYChartTheme } from '@visx/theme';
const legacyTheme = buildChartTheme({
backgroundColor: '#ffffff',
colors: ['#3b82f6', '#10b981', '#f59e0b', '#ef4444', '#8b5cf6'],
gridColor: '#f3f4f6',
gridColorDark: '#e5e7eb',
tickLength: 4,
});
const primitiveTheme = fromXYChartTheme(legacyTheme);
export function Dashboard() {
return (
<>
<XYChart theme={legacyTheme}>{/* existing chart */}</XYChart>
<ThemeScope theme={primitiveTheme}>{/* new primitive chart */}</ThemeScope>
</>
);
}The adapter is one-way and structural. @visx/theme does not import from @visx/xychart, and there
is no toXYChartTheme adapter.
Recipes
Line chart
import { AxisBottom } from '@visx/axis';
import { GridRows } from '@visx/grid';
import { LinePath } from '@visx/shape';
import { useAxisStyle, useColor, useGridStyle } from '@visx/theme/react';
export function RevenueLine({ data, xScale, yScale }) {
const axis = useAxisStyle('bottom');
const grid = useGridStyle();
const lineColor = useColor(0);
return (
<>
<GridRows scale={yScale} stroke={grid.stroke} strokeWidth={grid.strokeWidth} />
<LinePath
data={data}
x={(datum) => xScale(datum.date)}
y={(datum) => yScale(datum.revenue)}
stroke={lineColor}
strokeWidth={2}
/>
<AxisBottom
scale={xScale}
stroke={axis.stroke}
tickLength={axis.tickLength}
tickStroke={axis.tickStroke}
tickLabelProps={axis.tickLabelProps}
/>
</>
);
}Bar chart
import { AxisBottom, AxisLeft } from '@visx/axis';
import { Bar } from '@visx/shape';
import type { ChartConfig } from '@visx/theme';
import { useAxisStyle, useChartConfig } from '@visx/theme/react';
const seriesConfig = {
desktop: { label: 'Desktop' },
mobile: { label: 'Mobile' },
} satisfies ChartConfig<'desktop' | 'mobile'>;
export function TrafficBars({ data, xScale, yScale }) {
const xAxis = useAxisStyle('bottom');
const yAxis = useAxisStyle('left');
const { getColor, getLabel } = useChartConfig(seriesConfig, {
order: ['desktop', 'mobile'],
});
return (
<>
{data.map((datum) => (
<Bar
key={datum.browser}
x={xScale(datum.browser)}
y={yScale(datum.desktop)}
width={xScale.bandwidth()}
height={yScale(0) - yScale(datum.desktop)}
fill={getColor('desktop')}
aria-label={`${getLabel('desktop')} traffic`}
/>
))}
<AxisBottom scale={xScale} {...xAxis} />
<AxisLeft scale={yScale} {...yAxis} />
</>
);
}Area chart
import { AxisLeft } from '@visx/axis';
import { AreaClosed } from '@visx/shape';
import { useAxisStyle, useColor, useGridStyle } from '@visx/theme/react';
export function ConversionArea({ data, xScale, yScale }) {
const axis = useAxisStyle('left');
const grid = useGridStyle();
const fill = useColor(1);
const stroke = useColor('highlight');
return (
<>
<AreaClosed
data={data}
x={(datum) => xScale(datum.date)}
y={(datum) => yScale(datum.conversionRate)}
yScale={yScale}
fill={fill}
fillOpacity={0.18}
stroke={stroke}
strokeWidth={2}
/>
<line x1={0} x2="100%" y1={0} y2={0} stroke={grid.stroke} />
<AxisLeft
scale={yScale}
stroke={axis.stroke}
tickStroke={axis.tickStroke}
tickLabelProps={axis.tickLabelProps}
/>
</>
);
}File: packages/visx-theme/package.json
{
"name": "@visx/theme",
"version": "4.0.0",
"description": "visx theme utilities",
"sideEffects": false,
"main": "lib/index.js",
"module": "esm/index.js",
"types": "lib/index.d.ts",
"exports": {
".": {
"types": "./lib/index.d.ts",
"import": "./esm/index.js",
"require": "./lib/index.js"
},
"./react": {
"types": "./lib/react/index.d.ts",
"import": "./esm/react/index.js",
"require": "./lib/react/index.js"
}
},
"files": [
"lib",
"esm"
],
"repository": {
"type": "git",
"url": "git+https://github.com/airbnb/visx.git"
},
"keywords": [
"visx",
"react",
"visualizations",
"charts",
"theme"
],
"author": "@hshoff",
"license": "MIT",
"bugs": {
"url": "https://github.com/airbnb/visx/issues"
},
"homepage": "https://github.com/airbnb/visx#readme",
"dependencies": {
"@visx/kernel": "workspace:*"
},
"peerDependencies": {
"@types/react": "^18.0.0 || ^19.0.0",
"react": "^18.0.0 || ^19.0.0"
},
"publishConfig": {
"access": "public"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
},
"devDependencies": {
"@types/react": "^19.0.0"
}
}
File: packages/visx-theme/tsconfig.json
{
"compilerOptions": {
"declarationDir": "lib",
"outDir": "lib",
"rootDir": "src"
},
"exclude": [
"lib",
"test"
],
"extends": "../../tsconfig.options.json",
"include": [
"src//*",
"types//",
"../../types/**/"
],
"references": [
{
"path": "../visx-kernel"
}
]
}
File: packages/visx-theme/test/tsconfig.json
{
"compilerOptions": {
"composite": false,
"emitDeclarationOnly": false,
"noEmit": true,
"rootDir": ".",
"types": ["vitest/globals"]
},
"extends": "../../../tsconfig.options.json",
"include": ["/*", "../types//", "../../../types/**/"],
"references": [
{
"path": ".."
}
]
}
File: packages/visx-theme/test/tsconfig.typecheck.json
{
"compilerOptions": {
"composite": false,
"emitDeclarationOnly": false,
"noEmit": true,
"skipLibCheck": true,
"types": []
},
"extends": "../../../tsconfig.options.json",
"files": ["fromXYChartTheme.typecheck.ts"],
"references": [
{
"path": ".."
},
{
"path": "../../visx-xychart"
}
]
}
File: packages/visx-threshold/Readme.md
@visx/threshold
@visx/threshold allows for creation of Difference Charts in react, which highlight the delta
between two line series.
Installation
npm install --save @visx/thresholdFile: packages/visx-threshold/package.json
{
"name": "@visx/threshold",
"version": "4.0.0",
"description": "visx threshold",
"sideEffects": false,
"main": "lib/index.js",
"module": "esm/index.js",
"types": "lib/index.d.ts",
"exports": {
".": {
"types": "./lib/index.d.ts",
"import": "./esm/index.js",
"require": "./lib/index.js"
}
},
"files": [
"lib",
"esm"
],
"repository": "https://github.com/airbnb/visx",
"scripts": {
"docs": "cd ./docs && ../../../node_modules/.bin/react-docgen --exclude index.js ../src/ | ../../../scripts/buildDocs.sh"
},
"keywords": [
"visx",
"react",
"d3",
"visualizations",
"charts"
],
"author": "@hshoff",
"license": "MIT",
"dependencies": {
"@visx/clip-path": "workspace:",
"@visx/shape": "workspace:",
"classnames": "^2.3.1"
},
"peerDependencies": {
"@types/react": "^18.0.0 || ^19.0.0",
"react": "^18.0.0 || ^19.0.0"
},
"publishConfig": {
"access": "public"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
},
"devDependencies": {
"@types/react": "^19.0.0"
}
}
File: packages/visx-threshold/tsconfig.json
{
"compilerOptions": {
"declarationDir": "lib",
"outDir": "lib",
"rootDir": "src"
},
"exclude": [
"lib",
"test"
],
"extends": "../../tsconfig.options.json",
"include": [
"src//*",
"types//",
"../../types/**/"
],
"references": [
{
"path": "../visx-clip-path"
},
{
"path": "../visx-shape"
}
]
}
File: packages/visx-threshold/test/tsconfig.json
{
"compilerOptions": {
"composite": false,
"emitDeclarationOnly": false,
"noEmit": true,
"rootDir": ".",
"types": ["vitest/globals"]
},
"extends": "../../../tsconfig.options.json",
"include": ["/*", "../types//", "../../../types/**/"],
"references": [
{
"path": ".."
}
]
}