Skip to content

[Experiment] Component rendered tooltip #838

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 7 commits into
base: 8.0
Choose a base branch
from
Draft

Conversation

kingyue737
Copy link
Member

@kingyue737 kingyue737 commented Jun 7, 2025

Summary

This PR proposes a new echarts-tooltip component. The component provides a formatter method that can be used with ECharts' tooltip.formatter option, allowing users to define tooltip content using Vue's template syntax.

The slot props are what users passed to the formatter method. The component teleports its slot content to a detached DOM element so that it does not exist in the html body.

Example

<script setup>
const tooltipRef = useTemplateRef('tooltip')
const option = shallowRef({
  tooltip: {
    trigger: "axis",
    formatter: (params) => {
      const name = params[0].name;
      const value = params[0].value;
      return tooltipRef.value?.formatter({ name, value });
    },
  },
});
</script>

<template>
  <v-chart :option="option" />
  <v-chart-tooltip ref="tooltip" v-slot="{ name, value }">
    <div>
      <span>{{ name }}</span>
      <span>{{ value }}</span>
    </div>
  </v-chart-tooltip>
</template>

For a practical example, see the Line Chart in the demo preview which features a Pie Chart as its tooltip.

Design Rationale

Why a Separate Component?

  1. Users have multiple ways to define tooltip formatters, and a single ECharts instance may contain different types of charts. Adding a slot directly to VChart would make it difficult to handle these various use cases intuitively.

tooltip.formatter

  1. The showTip event doesn't provide sufficient information for implementing the approach suggested in Use Web Components without native class support detection #836 (comment).

  2. We may need to support ECharts' asynchronous tooltip formatting:

const option = shallowRef({
  tooltip: {
    formatter: function (params, ticket, callback) {
      fetch(`url?id=${params.dataIndex}`).then((remoteData) => {
        callback(ticket, tooltipRef.value.formatter(remoteData));
      });
      return "Loading";
    },
  },
});

By making it a separate component, users can:

  • Decide how to compose it with their chart options
  • Benefit from tree-shaking when the component is unused
  • Have more control over params passed to the formatter function

@Justineo , do you have any other ideas for us to try?

Copy link

vercel bot commented Jun 7, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
vue-echarts ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jun 14, 2025 0:28am

The limitation is that the tooltip detached from the current component tree, not provide/inject

will try teleport next
@Justineo
Copy link
Member

How about we go over the external API first?

@Justineo
Copy link
Member

  1. Users have multiple ways to define tooltip formatters, and a single ECharts instance may contain different types of charts. Adding a slot directly to VChart would make it difficult to handle these various use cases intuitively.

We could consider supporting multiple or dynamic slots—e.g., tooltip, tooltip-series-line, etc.—which could then map to the corresponding tooltip configurations at different levels. The idea would be to let slots fully override the tooltip formatters.

2. The showTip event doesn't provide sufficient information for implementing the approach suggested in Use Web Components without native class support detection #836 (comment).

From what I’ve seen, showTip is triggered whenever the pointer moves within the chart. Could you clarify what specific information is missing for our use case?

3. We may need to support ECharts' asynchronous tooltip formatting:

If we can implement tooltips as slots, we should be able to make the content reactive to async states or even render <Suspense>s.


The most tricky part I can think of is when and how to update the slot props when showTip is fired.

@kingyue737
Copy link
Member Author

We could consider supporting multiple or dynamic slots—e.g., tooltip, tooltip-series-line, etc.

I also considered this, but then I remembered that setOption can accept an array of options. So I decided to propose a separate component instead of designing a slot name convention, which might be a bit complicated 😂.

For multiple series of the same type but with different formatters, should we add a modifier like tooltip-series-line.[id]?

Most series support formatter for each single datum. But I think users can achieve similar functionality by using a series-level tooltip formatter and params.dataIndex. So we might not need to support it directly.

From what I’ve seen, showTip is triggered whenever the pointer moves within the chart. Could you clarify what specific information is missing for our use case?

I think the slotProps should be the params object from the tooltip.formatter callback if the slots belong to <VChart>. The payload of the showTip event is different from the params of the tooltip.formatter callback.

The most tricky part I can think of is when and how to update the slot props when showTip is fired.

We could override users' tooltip.formatter like this:

formatter(params) {
    // slotName.slotProps is a shallowRef
    slotName.slotProps.value = params

    return toHtml(slotContent)
}

The slot props would be updated whenever tooltip.formatter is called. So there’s no need to rely on the showTip event, just like here:

https://github.com/ecomfe/vue-echarts/pull/838/files#diff-bd261dd584a35b75c759fd268819ef41b77999d7e1fc0a703b7552b8449660daR11-R15

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants