|Kit
Chart

Interactions

Wiring a chart's own interaction callbacks into your UI, and an animated hover marker built on TanStack's own motion system.

Chart types live on chart types; this page is about wiring a chart's own interaction callbacks into your own UI, and about TanStack's own motion system.

Selecting a point

onFocusChange/onSelect fire with a ChartPoint — its datum is the original row, so any click-to-drill-in UI is just useState plus your own JSX below (or beside) the chart.

Tickets resolved per day

Click a bar to select it.

Code

const [selected, setSelected] = useState<ChartPoint<TicketDatum> | null>(null);

<Chart
  definition={ticketsResolvedChart}
  ariaLabel="Tickets resolved per day"
  height={280}
  color="purple"
  onSelect={setSelected}
/>
<p>
  {selected
    ? `${selected.datum.day}: ${selected.datum.resolved} tickets resolved`
    : 'Click a bar to select it.'}
</p>

An animated hover marker

This is TanStack's own opt-in motion system, documented here as exactly what it is — not something Chart defaults to. The marker TanStack paints on hover/focus is a new DOM node per point, not one node repositioned (verified directly against the rendered output — a plain CSS transition can't bridge that, since there's no persistent element for it to interpolate from). A mark's own motion option (below, on the crosshair mark) configures how it should glide, but does nothing by itself — TanStack's default SVG renderer paints every frame at its target position with no interpolation at all (also verified directly: sampling the marker mid-gesture showed it jump straight to the final value in a single frame). Actually running that motion needs @tanstack/charts/motion's own renderer, switched in through Chart's renderer prop:

Daily signups this month

Code

import { motion } from '@tanstack/charts/motion';

const chart = defineChart({
  marks: [
    lineY(dailySignups, { x: 'day', y: 'count', points: true }),
    crosshair({
      marker: { radius: 5 },
      motion: { transition: { type: 'tween', duration: 180, easing: 'ease-out' } },
    }),
  ],
  scales: {
    x: { scale: scaleLinear, nice: true, axis: { label: 'Day of month' } },
    y: { scale: scaleLinear, nice: true, grid: true, axis: { label: 'Signups' } },
  },
  tooltip,
});

<Chart definition={chart} ariaLabel="Daily signups this month" height={280} color="red" renderer={motion()} />

Hover across a few points to feel the difference against the plain (non-animated) charts on the other pages.

On this page