Customization
Tooltips and the hover readout
The value beside the cursor: three modes, and a template you write for what it says.
Read this page as Markdown, or take the whole documentation in one file.
The Value Beside the Cursor
A chart with a dozen lines on it already has a legend, and the legend carries every series and its value at the crosshair. What it cannot do is answer the question a reader asks by pointing: what is this one, here? The tooltip is that answer, and nothing else — it follows the pointer, and by default it says one line rather than all of them.
const chart = createFinancialChart(el, {
data: bars,
tooltip: {
mode: "hovered",
template: "{name} {value} 1d {value % value[-1]} 1w {value % value[-7]}",
},
});
Hovering the short-interest line then reads:
29 AUG
■ Short interest 12.50
1d +1.20% 1w -3.40%
The box carries three things: the hovered bar's date, formatted exactly as the time axis
labels it, then a row per series with that series' colour beside it, and under each row
whatever the template put after a newline. Set title: false to drop the date.
Three Modes
mode |
What shows | When to use it |
|---|---|---|
"none" |
Nothing. The default. | A chart that has not asked for a tooltip does not grow one. |
"hovered" |
One row, for the series under the pointer | A page with many series, where the reader is pointing at one of them |
"all" |
One row per series on the hovered pane | Two or three series that are read together, such as a spread |
hitRadius decides how close the pointer has to be, in pixels, for a series to count as
hovered. It defaults to 24, which is a comfortable target on a touch screen; lower it if
your series sit on top of each other and the wrong one keeps winning.
The Template
The text is a template you write, not a format we picked. It is deliberately small: it
reads a value, reads a value from earlier bars, compares two of them, and formats the
result. Anything past that is what formatter is for.
A placeholder is { term (operator term)? (|format)? }.
Fields
| Field | What it reads |
|---|---|
name |
The series title |
value |
The series' value at the hovered bar; the close, on a candlestick series |
open, high, low, close |
The bar's own fields |
volume |
The bar's volume |
index |
The bar's index in the data, which is occasionally useful while debugging |
time |
The hovered bar's timestamp |
A field can read backwards: value[-1] is the bar before the hovered one, value[-7]
seven bars before it. On a daily chart that is yesterday and last week; on a five-minute
chart it is five and thirty-five minutes ago. The offset counts bars, not days, because
that is what the chart has.
Averages
avg(field, n) is the mean of n bars ending at the term's offset, which is how a chart
says "against the week behind it".
tooltip: { mode: "hovered", template: "{name} {value|compact}
vs 1w average {value % avg(value[-1],7)}" }
avg(value[-1],7) is the seven bars before the hovered one, so today is compared with
the week it followed rather than with a week it is part of. A window that runs off the
start of the data has no mean, and the row says so with an em dash rather than averaging
whatever happens to be there: on the third bar of a chart, a week-average comparison is a
question the data cannot answer.
Volume carries this by default, so a volume bar reads as busy or quiet rather than as a number on its own.
Operators
| Operator | Meaning | Example |
|---|---|---|
% |
Percent change from the right value to the left, which is what a reader means by "change" | {value % value[-7]} → +4.10% |
- |
Difference | {value - value[-1]} → 1.20 |
/ |
Ratio | {high / low|num} → 1.03 |
Formats
A format follows a pipe: {value|compact}.
| Format | Output |
|---|---|
price |
The series' own price format, with its precision. The default for a value. |
pct |
+4.10%. The default when the operator is %. |
num |
1.03, rounded to two decimals |
compact |
1.25M, 3.40B |
raw |
The number as JavaScript prints it |
date, time |
For {time}: 2026-09-07, or 14:30 |
Two rules keep a template honest at the edges. A value the data does not have prints an em
dash rather than NaN, so a week-change placeholder on the eighth bar of the history says
so instead of lying. A placeholder that cannot be parsed is left on the page exactly as it
was written, which is how you find a typo without opening the console.
Two Lines, and a Template per Series
A newline in the template starts a quieter line under the value. That is where a change belongs: the value is what the reader came for, and the comparison is context.
template: "{name} {value}
1d {value % value[-1]} 1w {value % value[-7]}"
A series can also carry its own text, which overrides the chart's template for that row. A volume histogram wants a different sentence from a price line, and the chart cannot guess which.
chart.addSeries("histogram", {
title: "Volume",
tooltipTemplate: "{name} {value|compact}
vs 1w average {value % avg(value[-1],7)}",
});
When the Template Is Not Enough
formatter receives the same row the template would have rendered and returns a string, or
null to fall back to the template.
tooltip: {
mode: "hovered",
formatter: (row) =>
row.name === "Short interest"
? `${row.name} ${row.values.value?.toFixed(2)}% of free float`
: null,
}
The row carries name, time, index, the series' values at the hovered bar, its
priceFormat, and at(field, offset) — the same reader the template's offsets use.
Where It Sits
offset moves the box relative to the pointer, { x: 14, y: 14 } by default. The box
flips to the other side of the cursor by itself when it would leave the chart, so a series
at the right edge is still readable.
The tooltip is styled from the theme tokens, so it follows a theme change without a second configuration. See Colors, fonts and formatting.
On the Shell
The shell passes the option straight through, so a full chart application configures it in the same place as everything else.
const shell = createChartShell(el, {
symbol: "AAPL",
datafeed,
tooltip: { mode: "hovered", template: "{name} {value} {value % value[-1]}" },
});
Markers keep their own tooltips. A badge or a lane you hover still shows what it was given
in tooltip, whether or not series tooltips are on, because those two answer different
questions.