Tooltips
Victory supports multiple ways to show tooltips on your charts. Tooltips can be added to any Victory component, and can be customized to suit your needs. This guide will cover the basics of adding tooltips to your charts, as well as more advanced configurations.
Basic
The simplest way to add tooltips to a chart is to use VictoryTooltip as a labelComponent. By default, the labelComponent will display the label prop of the data point it is associated with, unless you specify a custom labels function.
<VictoryChart domain={{ x: [0, 11], y: [-10, 10] }} theme={VictoryTheme.clean} > <VictoryBar labelComponent={<VictoryTooltip />} data={[ { x: 2, y: 5 }, { x: 4, y: -6 }, { x: 6, y: 4 }, { x: 8, y: -5 }, { x: 10, y: 7 }, ]} labels={({ datum }) => datum.y} /> </VictoryChart>
Styles
VictoryTooltip can be styled using the style prop. The style prop accepts an object with data, labels, and flyout keys. The data key styles the data point, the labels key styles the text of the tooltip, and the flyout key styles the background of the tooltip.
<VictoryChart domain={{ x: [0, 11], y: [-10, 10] }} theme={VictoryTheme.clean} > <VictoryBar labelComponent={ <VictoryTooltip cornerRadius={({ datum }) => datum.x > 6 ? 0 : 20 } pointerLength={({ datum }) => datum.y > 0 ? 5 : 20 } flyoutStyle={{ stroke: ({ datum }) => datum.x === 10 ? "tomato" : "black", }} /> } data={[ { x: 2, y: 5, label: "right-side-up", }, { x: 4, y: -6, label: "upside-down", }, { x: 6, y: 4, label: "tiny" }, { x: 8, y: -5, label: "or a little \n BIGGER", }, { x: 10, y: 7, label: "automatically", }, ]} style={{ data: { width: 20 }, }} /> </VictoryChart>
Events
VictoryTooltip automatically attaches events to data components. When events of the same type are specified for data components, it is necessary to reconcile events so that tooltips still work. For web, the default tooltip events are:
static defaultEvents = [{
target: "data",
eventHandlers: {
onMouseOver: () => ({
target: "labels",
mutation: () => ({ active: true })
}),
onMouseOut: () => ({
target: "labels",
mutation: () => ({ active: undefined })
}),
onFocus: () => ({
target: "labels",
mutation: () => ({ active: true })
}),
onBlur: () => ({
target: "labels",
mutation: () => ({ active: undefined })
})
}
}];
When other onMouseOver and onMouseOut events are specified for data, the event returns described above must be added to the events for tooltips to continue to work properly.
<VictoryChart domain={{ x: [0, 11], y: [-10, 10] }} theme={VictoryTheme.clean} > <VictoryBar labelComponent={<VictoryTooltip />} data={[ { x: 2, y: 5, label: "A" }, { x: 4, y: -6, label: "B" }, { x: 6, y: 4, label: "C" }, { x: 8, y: -5, label: "D" }, { x: 10, y: 7, label: "E" }, ]} style={{ data: { width: 20 }, }} events={[ { target: "data", eventHandlers: { onMouseOver: () => { return [ { target: "data", mutation: () => ({ style: { fill: "gold", width: 30, }, }), }, { target: "labels", mutation: () => ({ active: true, }), }, ]; }, onMouseOut: () => { return [ { target: "data", mutation: () => {}, }, { target: "labels", mutation: () => ({ active: false, }), }, ]; }, }, }, ]} /> </VictoryChart>
Voronoi
Use VictoryVoronoiContainer to associate a mouse position with the data point(s)
closest to it. When this container is added to a chart, changes in mouse position will add the active
prop to data and label components closest to the current mouse position. The closeness of data
points to a given position is determined by calculating a voronoi diagram based on the data of
every child VictoryVoronoiContainer renders. This container is useful for adding hover interactions,
like tooltips, to small data points, or charts with dense or overlapping data.
See the full API here.
Basic
VictoryVoronoiContainer may be used with any Victory component that works with an x-y coordinate
system, and should be added as the containerComponent of the top-level component.
However, the component that uses it must be standalone
(standalone={true}), which is the default for all top-level Victory components.
<VictoryChart domain={{ x: [0, 5], y: [-5, 5] }} containerComponent={ <VictoryVoronoiContainer /> } theme={VictoryTheme.clean} > <VictoryScatter size={({ active }) => active ? 5 : 3 } labels={({ datum }) => datum.y} labelComponent={<VictoryTooltip />} data={[ { x: 1, y: -4 }, { x: 2, y: 4 }, { x: 3, y: 2 }, { x: 4, y: 1 }, ]} /> <VictoryScatter size={(datum, active) => active ? 5 : 3 } labels={({ datum }) => datum.y} labelComponent={<VictoryTooltip />} data={[ { x: 1, y: -3 }, { x: 2, y: 3 }, { x: 3, y: 3 }, { x: 4, y: 0 }, ]} /> <VictoryScatter data={[ { x: 1, y: 4 }, { x: 2, y: -4 }, { x: 3, y: -2 }, { x: 4, y: -3 }, ]} labels={({ datum }) => datum.y} labelComponent={<VictoryTooltip />} size={({ active }) => active ? 5 : 3 } /> </VictoryChart>
Follow Tooltips
When using VictoryVoronoiContainer with VictoryTooltip, you can add tooltips to your chart that follow the mouse position.
<VictoryChart theme={VictoryTheme.clean} domain={{ y: [0, 1] }} containerComponent={ <VictoryVoronoiContainer labels={({ datum }) => `Data ${datum.y}` } mouseFollowTooltips labelComponent={ <VictoryTooltip constrainToVisibleArea /> } /> } > <VictoryScatter data={[ { x: 1, y: 0 }, { x: 2, y: 0 }, { x: 3, y: 0 }, { x: 4, y: 0 }, { x: 5, y: 0 }, { x: 6, y: 0 }, { x: 7, y: 0 }, ]} style={{ data: { fill: VictoryTheme.clean.palette ?.colors.blue, }, }} size={({ active }) => active ? 8 : 3 } /> <VictoryScatter data={[ { x: 1, y: 0 }, { x: 2, y: 0 }, { x: 3, y: 1 }, { x: 4, y: 0 }, { x: 5, y: 0 }, { x: 6, y: 0 }, { x: 7, y: 0 }, ]} style={{ data: { fill: VictoryTheme.clean.palette ?.colors.red, }, }} size={({ active }) => active ? 5 : 3 } /> </VictoryChart>
Active Points
VictoryVoronoiContainer adds the active prop to any data point closest to the current mouse position. This prop can be used to style the active data point differently from the rest.
<VictoryChart domainPadding={{ y: 10 }} containerComponent={ <VictoryVoronoiContainer labels={({ datum }) => `${_.round(datum.x, 2)}, ${_.round( datum.y, 2, )}` } /> } theme={VictoryTheme.clean} > <VictoryScatter y={(datum) => Math.sin(2 * Math.PI * datum.x) } style={{ data: { fill: ({ active }) => active ? VictoryTheme.clean.palette ?.colors.red : VictoryTheme.clean.palette ?.colors.blue, }, }} /> </VictoryChart>
Multipoint Labels
VictoryVoronoiContainer can also be used to create multi-point labels when the labels prop is
provided. In the example below the voronoiDimension prop indicates that the voronoi diagram
will only be specific to the x dimension. For a given mouse position, all data matching the
associated x value will be activated regardless of y value. In the following example, this leads to
several tooltips being active at the same time. Provide a labels and (optionally) a
labelComponent prop to configure multi-point labels.
<VictoryChart domainPadding={{ y: 10 }} containerComponent={ <VictoryVoronoiContainer voronoiDimension="x" labels={({ datum }) => `y: ${datum.y}` } labelComponent={ <VictoryTooltip cornerRadius={0} flyoutStyle={{ fill: "white", }} /> } /> } theme={VictoryTheme.clean} > <VictoryLine data={[ { x: 1, y: 5, l: "one" }, { x: 1.5, y: 5, l: "one point five", }, { x: 2, y: 4, l: "two" }, { x: 3, y: -2, l: "three" }, ]} style={{ data: { stroke: "tomato", strokeWidth: ({ active }) => active ? 4 : 2, }, labels: { fill: "tomato" }, }} /> <VictoryLine data={[ { x: 1, y: -3, l: "red" }, { x: 2, y: 5, l: "green" }, { x: 3, y: 3, l: "blue" }, ]} style={{ data: { stroke: "blue", strokeWidth: ({ active }) => active ? 4 : 2, }, labels: { fill: "blue" }, }} /> <VictoryLine data={[ { x: 1, y: 5, l: "cat" }, { x: 2, y: -4, l: "dog" }, { x: 3, y: -2, l: "bird" }, ]} style={{ data: { stroke: "black", strokeWidth: ({ active }) => active ? 4 : 2, }, labels: { fill: "black" }, }} /> </VictoryChart>
Cursor
Use VictoryCursorContainer to add a cursor to a chart to inspect coordinates.
The cursor can either be a 2-dimensional crosshair, or a 1-dimensional line.
The cursor moves with the mouse (or on touch on mobile devices) along the visible domain of the chart.
The cursor can also display a label for the active coordinates using the cursorLabel prop.
See the full API here.
Line Charts
Using the VictoryCursorContainer component, you can add a 2D cursor to a line chart.
<VictoryChart containerComponent={ <VictoryCursorContainer cursorLabel={({ datum }) => `${_.round(datum.x, 2)}, ${_.round( datum.y, 2, )}` } /> } theme={VictoryTheme.clean} > <VictoryScatter y={(d) => d.x * d.x} /> </VictoryChart>
Dimension Limits
You can also use the cursorDimension prop to create a 1D cursor. This is useful for line charts where you only want to inspect one dimension. Note you can also set a defaultCursorValue to set the initial position of the cursor.
<VictoryChart containerComponent={ <VictoryCursorContainer cursorLabel={({ datum }) => `${_.round(datum.x, 2)}, ${_.round( datum.y, 2, )}` } cursorDimension="x" defaultCursorValue={0.3} /> } theme={VictoryTheme.clean} > <VictoryScatter y={(d) => d.x * d.x} /> </VictoryChart>
Bar Charts
You can also use the VictoryCursorContainer component with bar charts.
<VictoryChart horizontal theme={VictoryTheme.clean} domainPadding={{ x: 15 }} containerComponent={ <VictoryCursorContainer cursorLabel={({ datum }) => _.round(datum.x, 2) } cursorDimension="y" defaultCursorValue={3} /> } > <VictoryGroup offset={10}> <VictoryBar data={[ { x: 1, y: 5, l: "one" }, { x: 2, y: 4, l: "two" }, { x: 3, y: -2, l: "three" }, ]} /> <VictoryBar data={[ { x: 1, y: -3, l: "red" }, { x: 2, y: 5, l: "green" }, { x: 3, y: 3, l: "blue" }, ]} /> <VictoryBar data={[ { x: 1, y: 5, l: "cat" }, { x: 2, y: -4, l: "dog" }, { x: 3, y: -2, l: "bird" }, ]} /> </VictoryGroup> </VictoryChart>
Scatter Charts
You can also use the VictoryCursorContainer component with scatter charts. Note how we can apply the container directly to the VictoryScatter component.
<VictoryScatter theme={VictoryTheme.clean} style={{ data: { fill: ({ active }) => active ? VictoryTheme.clean.palette ?.colors.teal || "teal" : VictoryTheme.clean.palette ?.colors.purple || "purple", }, }} containerComponent={ <VictoryCursorContainer theme={VictoryTheme.clean} cursorLabel={({ datum }) => _.round(datum.x, 2) } defaultCursorValue={1} /> } data={[ { x: -3, y: 2 }, { x: 0, y: -2 }, { x: -8, y: 1 }, { x: -2, y: -3 }, { x: 7, y: 5 }, { x: -8, y: 6 }, { x: -1, y: 3 }, { x: -4, y: -5 }, { x: -6, y: -5 }, ]} />
Events
You can also use the onCursorChange prop to listen to cursor changes and inspect the values.
function App() { const [cursorValue, setCursorValue] = React.useState(null); function onCursorChange(value) { setCursorValue(value); } return ( <VictoryChart theme={VictoryTheme.clean} containerComponent={ <VictoryCursorContainer cursorLabel={({ datum }) => _.round(datum.x, 2) } cursorLabelOffset={15} onCursorChange={ onCursorChange } /> } > <VictoryGroup> <VictoryScatter style={{ data: { fill: VictoryTheme.clean .palette?.colors.red, }, }} data={[ { x: 1, y: -5 }, { x: 2, y: 4 }, { x: 3, y: 2 }, { x: 4, y: 0 }, { x: 5, y: 1 }, { x: 6, y: -3 }, { x: 7, y: 3 }, ]} /> <VictoryScatter style={{ data: { fill: VictoryTheme.clean .palette?.colors.yellow, }, }} data={[ { x: 1, y: -3 }, { x: 2, y: 5 }, { x: 3, y: 3 }, { x: 4, y: 0 }, { x: 5, y: -2 }, { x: 6, y: -2 }, { x: 7, y: 5 }, ]} /> <VictoryScatter data={[ { x: 1, y: 5 }, { x: 2, y: -4 }, { x: 3, y: -2 }, { x: 4, y: -3 }, { x: 5, y: -1 }, { x: 6, y: 3 }, { x: 7, y: -3 }, ]} /> </VictoryGroup> {cursorValue && ( <VictoryLabel x={20} y={20} text={JSON.stringify( cursorValue, )} /> )} </VictoryChart> ); } render(<App />);
Custom Components
VictoryTooltip is composed of VictoryLabel and the primitive Flyout component. Both of these components are highly configurable, but may also be replaced if necessary.
Custom Flyout
An example of replacing the default Flyout component with a custom component.
const colors = VictoryTheme.clean.palette.cool; function CustomFlyout(props) { const { x, y, orientation } = props; const newY = orientation === "bottom" ? y - 35 : y + 35; return ( <g> <circle cx={x} cy={newY} r="20" stroke={colors[0]} fill="none" /> <circle cx={x} cy={newY} r="25" stroke={colors[1]} fill="none" /> <circle cx={x} cy={newY} r="30" stroke={colors[2]} fill="none" /> </g> ); } function App() { return ( <VictoryChart domain={{ x: [0, 11], y: [-10, 10], }} theme={VictoryTheme.clean} > <VictoryBar labelComponent={ <VictoryTooltip flyoutComponent={ <CustomFlyout /> } /> } data={[ { x: 2, y: 5, label: "A" }, { x: 4, y: -6, label: "B" }, { x: 6, y: 4, label: "C" }, { x: 8, y: -5, label: "D" }, { x: 10, y: 7, label: "E" }, ]} style={{ data: { width: 20 }, }} /> </VictoryChart> ); } render(<App />);
Custom Label
An example of using custom labels with a donut chart.
function CustomLabel(props) { return ( <g> <VictoryLabel {...props} /> <VictoryTooltip {...props} x={226} y={197} orientation="top" pointerLength={0} cornerRadius={50} flyoutWidth={100} flyoutHeight={100} flyoutStyle={{ fill: "#bdbdbd", }} /> </g> ); } CustomLabel.defaultEvents = VictoryTooltip.defaultEvents; function App() { return ( <VictoryPie theme={VictoryTheme.clean} style={{ labels: { fill: "white" }, }} innerRadius={80} labelRadius={100} radius={140} labelComponent={<CustomLabel />} data={[ { x: 1, y: 5, label: "Dogs" }, { x: 2, y: 4, label: "Cats" }, { x: 3, y: 2, label: "Rabbits", }, { x: 4, y: 3, label: "Birds" }, { x: 5, y: 1, label: "Snakes" }, ]} /> ); } render(<App />);
Custom Wrapping
The events that control VictoryTooltip are stored on the static defaultEvents property. Wrapped instances of VictoryTooltip will need to replicate or hoist this property in order to add automatic events to the components that use them.
function CustomTooltip(props) { const { x, y } = props; const rotation = `rotate(45 ${x} ${y})`; return ( <g transform={rotation}> <VictoryTooltip {...props} renderInPortal={false} /> </g> ); } CustomTooltip.defaultEvents = VictoryTooltip.defaultEvents; function App() { return ( <VictoryChart domain={{ x: [0, 11], y: [-10, 10], }} theme={VictoryTheme.clean} > <VictoryBar labelComponent={ <CustomTooltip /> } data={[ { x: 2, y: 5, label: "A" }, { x: 4, y: -6, label: "B" }, { x: 6, y: 4, label: "C" }, { x: 8, y: -5, label: "D" }, { x: 10, y: 7, label: "E" }, ]} /> </VictoryChart> ); } render(<App />);
Victory Native
In Victory Native tooltips are much more reliable when using VictoryVoronoiContainer. Using VictoryVoronoiContainer registers all touch events on the container itself, which mitigates interference with other chart elements, which can be a problem on some platforms. Showing the closest data point with VictoryVoronoiContainer also increases the tap targets for the tooltip, which can otherwise be quite small. Set VictoryVoronoiContainer as the containerComponent prop on the outermost Victory component.
<VictoryChart
containerComponent={
<VictoryVoronoiContainer />
}
>
<VictoryScatter
labelComponent={<VictoryTooltip />}
labels={({ datum }) => datum.y}
style={{
data: {
fill: ({ datum }) => datum.fill,
},
}}
data={[
{ x: 1, y: 3 },
{ x: 3, y: 5 },
]}
/>
</VictoryChart>