# How to Format ECharts Tooltips with Custom HTML Templates

> Learn to format ECharts tooltips using custom HTML templates. Explore string templates, synchronous and asynchronous functions for dynamic data visualization.

- Repository: [The Apache Software Foundation/echarts](https://github.com/apache/echarts)
- Tags: how-to-guide
- Published: 2026-03-04

---

**ECharts formats tooltips through a `formatter` option that accepts string templates with placeholders (`{a}`, `{b}`, `{c}`), synchronous functions returning HTML strings, or asynchronous functions using a `callback` parameter, with content rendered via `createTooltipMarkup` in [`src/component/tooltip/tooltipMarkup.ts`](https://github.com/apache/echarts/blob/main/src/component/tooltip/tooltipMarkup.ts) and automatically HTML-encoded via `encodeHTML` to prevent XSS.**

ECharts provides flexible tooltip customization through its `formatter` option, allowing developers to inject custom HTML templates into chart tooltips. According to the apache/echarts source code, the tooltip markup engine processes these formatters through a secure pipeline that converts templates into either DOM elements or canvas-rich text. Understanding how `buildTooltipMarkup` and `TooltipMarkupStyleCreator` interact with your custom HTML ensures you can create rich, interactive tooltips without compromising security.

## The Formatter API

The `tooltip.formatter` option supports three distinct patterns for generating content:

- **String template**: Static HTML containing placeholders like `{a}` (series name), `{b}` (data name), `{c}` (value), and `{d}` (percent).
- **Function**: JavaScript function receiving data parameters and returning an HTML string.
- **Asynchronous function**: Function receiving a `callback` parameter to resolve content after async operations.

All formatter types ultimately pass through `createTooltipMarkup` in [`src/component/tooltip/tooltipMarkup.ts`](https://github.com/apache/echarts/blob/main/src/component/tooltip/tooltipMarkup.ts), which builds a markup tree before rendering.

## String Template Formatters

String templates provide the simplest approach for basic HTML formatting. The template engine replaces placeholders with actual data values before passing the result through the markup builder.

```javascript
option = {
    tooltip: {
        trigger: 'axis',
        formatter: `
            <div style="font-weight:bold;">{a}</div>
            <div>{b} : {c} ({d}%)</div>
        `
    },
    xAxis: { type: 'category', data: ['Mon', 'Tue', 'Wed'] },
    yAxis: { type: 'value' },
    series: [{ 
        type: 'bar', 
        name: 'Sales', 
        data: [120, 200, 150] 
    }]
};

```

In [`src/component/tooltip/tooltipMarkup.ts`](https://github.com/apache/echarts/blob/main/src/component/tooltip/tooltipMarkup.ts) (lines 72–78), the string is processed by `buildSection` and automatically HTML-encoded via `encodeHTML` to prevent injection attacks while preserving your template structure.

## Function-Based Formatters

For dynamic content requiring calculations or conditional logic, use a function formatter defined in [`src/component/tooltip/TooltipModel.ts`](https://github.com/apache/echarts/blob/main/src/component/tooltip/TooltipModel.ts) (lines 35–38).

### Synchronous Functions

The function receives a `params` object (or array for axis triggers) containing `seriesName`, `name`, `value`, and other metadata:

```javascript
option = {
    tooltip: {
        trigger: 'item',
        formatter: function (params) {
            return `
                <div style="color:#fff;background:#333;padding:5px;">
                    <strong>${params.seriesName}</strong><br/>
                    ${params.name}: <em>${params.value}</em>
                </div>`;
        }
    },
    series: [{ 
        type: 'pie', 
        data: [
            {value: 335, name: 'A'}, 
            {value: 123, name: 'B'}
        ] 
    }]
};

```

### Asynchronous Functions with Callback

For data fetched from APIs, the formatter accepts a third `callback` parameter. The implementation in [`test/tooltip.html`](https://github.com/apache/echarts/blob/main/test/tooltip.html) (lines 998–1013) demonstrates this pattern:

```javascript
option = {
    tooltip: {
        trigger: 'axis',
        formatter: function (params, ticket, callback) {
            setTimeout(function () {
                const html = `
                    <div>Fetched at ${new Date().toLocaleTimeString()}</div>
                    <div>Sum: ${params.reduce((s, p) => s + p.value, 0)}</div>`;
                callback(ticket, html);
            }, 800);
            return 'loading…';
        }
    },
    series: [{ type: 'line', data: [10, 20, 30] }]
};

```

The `callback(ticket, html)` resolves the tooltip content while the initial return value displays temporary loading text.

## Render Modes and Security

ECharts supports two rendering paths that affect how your HTML template becomes visual output.

### HTML Mode and XSS Protection

When `renderMode` is `'html'` (default), the tooltip renders as a DOM element. The `encodeHTML` function in [`src/component/tooltip/tooltipMarkup.ts`](https://github.com/apache/echarts/blob/main/src/component/tooltip/tooltipMarkup.ts) (lines 72–78) escapes all user-provided placeholder values before insertion, preventing XSS attacks while allowing your literal HTML markup to function normally.

### RichText Mode for Canvas/SVG

For canvas-based charts without DOM overlay, set `renderMode: 'richText'`. In this mode, `TooltipMarkupStyleCreator` (lines 150–180 in [`tooltipMarkup.ts`](https://github.com/apache/echarts/blob/main/tooltipMarkup.ts)) converts your formatter output into styled text fragments rather than HTML elements:

```javascript
option = {
    tooltip: {
        renderMode: 'richText',
        formatter: '{a}<br/>{b}: {c}'
    },
    series: [{ type: 'scatter', data: [[10, 20], [15, 25]] }]
};

```

Both modes share the same formatter syntax, but `buildTooltipMarkup` generates different internal representations depending on the render target.

## Key Implementation Files

Understanding the ECharts tooltip architecture requires familiarity with these specific files:

- **[`src/component/tooltip/TooltipModel.ts`](https://github.com/apache/echarts/blob/main/src/component/tooltip/TooltipModel.ts)**: Defines the `tooltip` option schema, including `formatter` and `renderMode` defaults (lines 35–38).
- **[`src/component/tooltip/tooltipMarkup.ts`](https://github.com/apache/echarts/blob/main/src/component/tooltip/tooltipMarkup.ts)**: Core markup engine containing `createTooltipMarkup`, `buildTooltipMarkup`, `encodeHTML`, and `TooltipMarkupStyleCreator` (lines 27–33, 72–78, 150–180).
- **[`test/tooltip.html`](https://github.com/apache/echarts/blob/main/test/tooltip.html)**: Live demonstration of async formatters and edge cases (lines 998–1013).

## Summary

- **String templates** use placeholders (`{a}`, `{b}`, `{c}`) for simple HTML formatting without JavaScript logic.
- **Function formatters** provide full control via `params` objects and return literal HTML strings.
- **Async formatters** utilize the `callback(ticket, html)` pattern demonstrated in [`test/tooltip.html`](https://github.com/apache/echarts/blob/main/test/tooltip.html) for deferred content loading.
- **HTML mode** automatically encodes placeholder values via `encodeHTML` in [`tooltipMarkup.ts`](https://github.com/apache/echarts/blob/main/tooltipMarkup.ts) to prevent XSS.
- **RichText mode** converts output through `TooltipMarkupStyleCreator` for canvas/SVG rendering without DOM elements.

## Frequently Asked Questions

### How do I access the series color in a custom tooltip formatter?

The `params` object passed to function formatters includes a `color` property containing the item's assigned color. Access it via `params.color` to style markers or borders in your HTML template.

### Can I use JavaScript event listeners in tooltip HTML?

Yes, but only when `renderMode` is set to `'html'`. The resulting DOM element supports standard HTML including button and anchor tags with event handlers. Avoid inline event attributes in favor of delegated events due to the tooltip's dynamic DOM insertion.

### Why is my HTML showing as plain text instead of rendering?

Verify that `renderMode` is not set to `'richText'`, which converts HTML tags to literal text rather than DOM elements. Also ensure your `tooltip.formatter` returns a string, not a DOM node, as ECharts handles the insertion internally.

### What is the performance impact of async tooltip formatters?

Async formatters trigger DOM updates via `callback`, which causes tooltip repositioning after content loads. For high-frequency charts with real-time data, async tooltips may cause flickering or layout shifts; consider pre-fetching data or using synchronous formatters with cached values instead.