Advanced Tooltip Configuration and Customization in VChart
This article explains the fundamentals of VChart tooltips, demonstrates how to enable enterable tooltips with Amazon‑style safety triangles, shows flexible content and style patterns, and provides methods for custom DOM manipulation and fully custom tooltip handlers to meet diverse frontend data‑visualisation needs.
Preface
Tooltips are a common GUI element that display detailed data when a user hovers over a chart element (desktop) or long‑presses it (mobile). They greatly enrich chart data presentation and interaction, and most major chart libraries (e.g., ECharts, G2) already provide built‑in tooltip support. VChart offers even more flexible tooltip configurations.
Example 1: Enterable Tooltip and Amazon’s Safety Triangle
By default VChart tooltips do not respond to mouse events, but the enterable property can be set to allow users to move the mouse into the tooltip for additional interactions such as clicking buttons or copying data.
When enterable: false the mouse cannot enter the tooltip area (see GIF). Setting enterable: true creates a “safety triangle” between the cursor and the two tooltip corners, allowing the tooltip to stay visible while the mouse moves into it.
const spec = {
type: 'waterfall',
data: [], // data omitted
legends: { visible: true, orient: 'bottom' },
xField: 'x',
yField: 'y',
seriesField: 'type',
total: { type: 'field', tagField: 'total' },
title: { visible: true, text: 'Chinese quarterly GDP in 2022' },
tooltip: { enterable: true }
};
const vchart = new VChart(spec, { dom: CONTAINER_ID });
vchart.renderSync();The enterable tooltip mimics Amazon’s menu interaction: a triangular region is formed by the cursor and the tooltip’s two corners; if the cursor moves into this region, the tooltip remains open, otherwise it closes promptly.
Example 2: Flexible Pattern – Free Configuration of Content and Style
VChart’s tooltip can be extensively customized. The demo at https://www.visactor.io/vchart/demo/tooltip/custom-tooltip shows a chart with a y‑axis mark line at y = 10000 and the following requirements:
Sort data items from large to small.
Highlight items above the mark line in red (conditional formatting).
Append a final line displaying the mark‑line value.
The tooltip position is fixed: dimension tooltip above the cursor, mark tooltip below the data point.
const markLineValue = 10000;
const spec = {
type: 'line',
data: {
values: [
{ type: 'Nail polish', country: 'Africa', value: 4229 },
// other data omitted
]
},
stack: false,
xField: 'type',
yField: 'value',
seriesField: 'country',
legends: [{ visible: true, position: 'middle', orient: 'bottom' }],
markLine: [{
y: markLineValue,
endSymbol: { visible: false },
line: { style: {/* style omitted */} }
}],
tooltip: {
mark: {
title: { value: datum => datum.type },
content: [{ key: datum => datum.country, value: datum => datum.value }]
},
dimension: {
title: { value: datum => datum.type },
content: [{ key: datum => datum.country, value: datum => datum.value }],
updateContent: prev => {
// sort descending
prev.sort((a, b) => b.value - a.value);
// conditional format
prev.forEach(item => {
if (item.value >= markLineValue) {
item.valueStyle = { fill: 'red' };
}
});
// add extra line for mark line
prev.push({
key: 'Mark Line',
value: markLineValue,
keyStyle: { fill: 'orange' },
valueStyle: { fill: 'orange' },
shapeType: 'M44.3,22.1H25.6V3.3h18.8V22.1z M76.8,3.3H58v18.8h18.8V3.3z M99.8,3.3h-9.4v18.8h9.4V3.3z M12.9,3.3H3.5v18.8h9.4V3.3z',
shapeColor: 'orange',
hasShape: true
});
}
}
}
};
const vchart = new VChart(spec, { dom: CONTAINER_ID });
vchart.renderSync();The updateContent callback runs after the tooltip data is assembled, allowing sorting, conditional styling, and adding extra rows.
Tooltip Style and Position
Tooltip position can be set via the position and positionAt fields. Example:
{
tooltip: {
mark: { position: 'bottom', positionAt: 'mark' },
dimension: { position: 'top', positionAt: 'pointer' }
}
}Overall style can be customized under tooltip.style (refer to the official docs).
Example 3: Extending the Tooltip DOM Tree
VChart supports two rendering modes: DOM (browser) and Canvas (mini‑programs, Node). For DOM mode, a callback updateElement allows developers to modify the tooltip’s DOM after it is created.
{
tooltip: {
enterable: true,
updateElement: (el, actualTooltip, params) => {
if (actualTooltip.activeType === 'dimension') {
const { changePositionOnly, dimensionInfo } = params;
if (changePositionOnly) return;
// adjust size
el.style.width = 'auto';
el.style.height = 'auto';
el.style.minHeight = 'auto';
el.getElementsByClassName('value-box')[0].style.flex = '1';
for (const valueLabel of el.getElementsByClassName('value')) {
valueLabel.style.maxWidth = 'none';
}
// remove previous custom element
if (el.lastElementChild?.id === 'button-container') {
el.lastElementChild.remove();
}
// add new custom element (Google search link)
const div = document.createElement('div');
div.id = 'button-container';
div.style.margin = '10px -10px 0px';
div.style.padding = '10px 0px 0px';
div.style.borderTop = '1px solid #cccccc';
div.style.textAlign = 'center';
div.innerHTML = `<a href="https://www.google.com/search?q=${dimensionInfo[0]?.value}" style="text-decoration: none" target="_blank">Search with <b>Google</b></a>`;
el.appendChild(div);
} else {
// clean up for mark tooltip
if (el.lastElementChild?.id === 'button-container') {
el.lastElementChild.remove();
}
}
}
}
}The callback runs each time the tooltip is shown or updated, giving full control over the DOM while preserving VChart’s positioning logic.
Example 4: Full Custom Tooltip Rendering
For ultimate flexibility, developers can replace VChart’s built‑in tooltip with a custom handler via setTooltipHandler . The handler must implement showTooltip , hideTooltip , and release methods.
vchart.setTooltipHandler({
showTooltip: (activeType, tooltipData, params) => {
const tooltip = document.getElementById('tooltip');
tooltip.style.left = params.event.x + 'px';
tooltip.style.top = params.event.y + 'px';
let data = [];
if (activeType === 'dimension') {
data = tooltipData[0]?.data[0]?.datum ?? [];
} else if (activeType === 'mark') {
data = tooltipData[0]?.datum ?? [];
}
tooltipChart.updateData('tooltipData', data.map(({ type, value, month }) => ({ type, value, month })));
tooltip.style.visibility = 'visible';
},
hideTooltip: () => {
const tooltip = document.getElementById('tooltip');
tooltip.style.visibility = 'hidden';
},
release: () => {
tooltipChart.release();
const tooltip = document.getElementById('tooltip');
tooltip.remove();
}
});This approach gives complete control over rendering, data processing, and lifecycle management.
Other Features Overview
Dimension Tooltip on Any Axis
VChart can trigger dimension tooltips on continuous axes, time axes, or any axis within a chart, unlike many libraries that limit it to discrete axes.
Long Content Support – Multi‑Line and Scroll
When tooltip content is lengthy, VChart can display multi‑line text and enable a scrollable region, improving readability.
Conclusion
Tooltips play a crucial role in enhancing chart usability. This article covered basic usage, the underlying design, and multiple customization levels in VChart. For more advanced scenarios, refer to the official demos and documentation.
While tooltips are powerful, overusing them may harm user experience; they should appear only when they add clear value.
Contact & Community
We welcome feedback via the VisActor WeChat subscription account, official website https://www.visactor.io/ , and Feishu group (QR code below). Star the GitHub repository https://github.com/VisActor/VChart for support.
ByteFE
Cutting‑edge tech, article sharing, and practical insights from the ByteDance frontend team.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.