Legends, selection, brushes and zoom work the same way on every TanStack chart, through the kit's Chart components. The options below go into the chart's TanStack definition, written the way TanStack documents it.
Install
npx antuikit@latest init
npx antuikit@latest add tanstack-chart
The first command installs AntuikitProvider and the theme tokens. The second adds the chart components and TanStack Charts itself.
Controlled state
Every control on this page keeps its value in your state, not in the chart. controlledSignal pairs the current value with a callback that receives the next one. Store it, and rebuild the definition from it in useMemo, the way a controlled input works.
import { controlledSignal } from "@tanstack/charts/interaction/signal"
The callback's second argument carries a reason. For a drag it is preview while the pointer moves, then commit or cancel. Keep the chart on the last committed value and use previews for live text, so a cancelled drag puts everything back.
Toggle series from the legend
interactiveColorLegend replaces the color legend with buttons that hide and show series. It works on marks whose color names the series.
import { interactiveColorLegend } from "@tanstack/charts/legend"
color: {
domain: industries,
legend: interactiveColorLegend({
visible: controlledSignal(visible, setVisible),
placement: "bottom",
ariaLabel: "Series visibility",
}),
}
A hidden series keeps its color and its place in the scale domains. Set the value scale's domain yourself when the chart should not rescale at all.
hover: "series" highlights a series while the pointer is on its button or the button has focus.
Select a point
keyedSelection turns a click, Enter or Space on a point into a selected key. whenSelected wraps a mark so it draws only the selected point, which makes it the highlight. Anything else on the page, such as a table, can set the same key.
import { keyedSelection, whenSelected } from "@tanstack/charts/selection"
A click on empty space proposes null. Add a Clear selection button that sets the same state, for readers who do not know that.
Axis pointer and synchronized cursors
focusGuideX draws a line at the focused x value. With focus: "group-x" and no distance limit it snaps to the nearest date from anywhere in the plot, and one tooltip lists every series there.
import { focusGuideX } from "@tanstack/charts/focus/guide"
To mark the same date in two stacked charts, draw both as views of one viewGrid and give the second share: { x: "current" }, the id of the first. For charts that are separate components, create one controller with createChartCursor() and pass it to each definition's cursor option with use: cursorHost, mode: "focus" and match: "x".
Free cursor
continuousCursor follows any position in the plot, between data points too. Both scales must be numeric or time scales. Hovering sends previews, and a click commits a position and pins the cursor.
import { continuousCursor } from "@tanstack/charts/interaction/cursor"
range follows the drag for the summary text, and committed drives the chart. keyboard: false on the definition turns off point navigation, so the brush is the chart's only control. For focus and context, put the brush on a small overview chart and use committed as the domain of a larger one.
Zoom and pan
zoomX proposes a new x window as the reader zooms and pans. Use the window as the x scale's domain, and set clip so marks outside it are cut off.
import { zoomX } from "@tanstack/charts/interaction/zoom"
extent is the full range, and scaleExtent caps the zoom at eight times here.
The wheel zooms only once the chart has focus. On a page that scrolls, wheelActivation: "modifier" zooms while Control or Command is held instead. Avoid "always" there.
Pass every proposal to state, previews included, so the chart moves with the gesture.
Handles and scrubbers
handleX is one draggable value on a track, such as a playhead or an event's end date. Its value must be one of values. cross places the track below the plot with edge, or across it at a y value.
import { handleX } from "@tanstack/charts/interaction/handle"
if (reason.type === "commit") setFrame(dates.indexOf(next))
}),
values: dates,
cross: { edge: "bottom", offset: 34 },
ariaLabel: "Timeline frame",
format: (date) => formatDay(date),
}),
],
The chart does not play anything itself. Keep the timer in your component, stop it when the reader drags or reaches the last value, and show a Play and Pause button.
Live data
Append rows to your state and rebuild the definition. Keep each row's key stable so surviving points keep their place and focus. Set the x domain yourself to choose what the reader sees: a fixed window, the latest week, or everything so far.
API
The options of each control. TanStack Charts' documentation has the full reference.