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>