Chart tooltip
Inspect chart observations with registry labels and caller-formatted values by pointer or keyboard.
On this page
- Illustrative amount
Code
import { ChartContainer, type ChartRegistry } from "@bosunkit/components/chart-container";
import { ChartTooltip } from "@bosunkit/components/chart-tooltip";
import { ChartLegend } from "@bosunkit/components/chart-legend";
import { DataTable, type Column } from "@bosunkit/components/data-table";
import * as Recharts from "recharts";
import type { ReactElement } from "react";
export const description: string =
"A custom Recharts area uses the same registry, token colors and formatted tooltip as the standard charts.";
const values: Readonly<Record<number, string>> = {
0: "0",
1: "1",
2: "2",
3: "3",
4: "4",
5: "5",
6: "6",
7: "7",
8: "8",
};
const formatValue: (value: number) => string = (value: number): string => values[value] ?? "";
const formatCategory: (value: string | number) => string = (value: string | number): string =>
typeof value === "string" ? value : "";
const config: ChartRegistry = { amount: { label: "Illustrative amount", formatValue, color: "03" } };
const data: { day: string; amount: number | null }[] = [
{ day: "Mon", amount: 2 },
{ day: "Tue", amount: 4 },
{ day: "Wed", amount: 3 },
{ day: "Thu", amount: 6 },
];
const columns: readonly Column[] = [
{ key: "day", label: "Day" },
{
key: "amount",
label: "Illustrative amount",
align: "end",
render: (row: Record<string, unknown>): string => {
const { amount }: Record<string, unknown> = row;
return typeof amount === "number" ? formatValue(amount) : "Not counted";
},
},
];
export default function ComposedArea(): ReactElement {
return (
<div>
<ChartContainer
config={config}
label="Illustrative daily amounts"
formatCategory={formatCategory}
missingValueText="Not counted"
>
<Recharts.AreaChart data={data} accessibilityLayer aria-label="Illustrative daily amounts">
<Recharts.CartesianGrid vertical={false} />
<Recharts.XAxis dataKey="day" tickFormatter={formatCategory} axisLine={false} tickLine={false} />
<Recharts.YAxis domain={[0, 8]} tickFormatter={formatValue} axisLine={false} tickLine={false} width="auto" />
<Recharts.Area
dataKey="amount"
type="linear"
stroke="var(--color-amount)"
fill="var(--color-amount)"
fillOpacity={0.2}
isAnimationActive={false}
connectNulls={false}
/>
<ChartTooltip />
</Recharts.AreaChart>
</ChartContainer>
<ChartLegend config={config} label="Amount series" />
<section aria-label="Illustrative source values">
<DataTable columns={columns} rows={data} />
</section>
</div>
);
}
The chart tooltip installs formatted content into Recharts inspection. It reads the registry, selected keys, category formatter and missing-value text from ChartContainer, or accepts them explicitly. It never falls back to locale-independent number strings.
The tooltip also resolves pie categories from their registry keys. Typed interval definitions add caller-formatted bounds under the associated series; unavailable bounds retain the missing-value description.
Use
Each row uses the series' registry name, color and pattern. Zero is an observation; missing values use the caller's text. Category headings state the time reference when they are times. Keyboard inspection remains enabled on the chart root. A source table makes the values available without hover, including categories whose observations are all missing.
shared={false} inspects one hovered mark on Recharts roots that support item inspection, including BarChart.
It omits the shared axis cursor, shows only that mark's registry entry and allows the tooltip to extend vertically
beyond a compact plot. The error breakdown
uses this mode with an active segment outline and caller-formatted counts and percentages. Leaving shared unset
uses the chart root's default, including shared inspection for line charts.
Examples
Composition
- Illustrative amount
Code
import { ChartContainer, type ChartRegistry } from "@bosunkit/components/chart-container";
import { ChartTooltip } from "@bosunkit/components/chart-tooltip";
import { ChartLegend } from "@bosunkit/components/chart-legend";
import { DataTable, type Column } from "@bosunkit/components/data-table";
import * as Recharts from "recharts";
import type { ReactElement } from "react";
export const description: string =
"A custom Recharts area uses the same registry, token colors and formatted tooltip as the standard charts.";
const values: Readonly<Record<number, string>> = {
0: "0",
1: "1",
2: "2",
3: "3",
4: "4",
5: "5",
6: "6",
7: "7",
8: "8",
};
const formatValue: (value: number) => string = (value: number): string => values[value] ?? "";
const formatCategory: (value: string | number) => string = (value: string | number): string =>
typeof value === "string" ? value : "";
const config: ChartRegistry = { amount: { label: "Illustrative amount", formatValue, color: "03" } };
const data: { day: string; amount: number | null }[] = [
{ day: "Mon", amount: 2 },
{ day: "Tue", amount: 4 },
{ day: "Wed", amount: 3 },
{ day: "Thu", amount: 6 },
];
const columns: readonly Column[] = [
{ key: "day", label: "Day" },
{
key: "amount",
label: "Illustrative amount",
align: "end",
render: (row: Record<string, unknown>): string => {
const { amount }: Record<string, unknown> = row;
return typeof amount === "number" ? formatValue(amount) : "Not counted";
},
},
];
export default function ComposedArea(): ReactElement {
return (
<div>
<ChartContainer
config={config}
label="Illustrative daily amounts"
formatCategory={formatCategory}
missingValueText="Not counted"
>
<Recharts.AreaChart data={data} accessibilityLayer aria-label="Illustrative daily amounts">
<Recharts.CartesianGrid vertical={false} />
<Recharts.XAxis dataKey="day" tickFormatter={formatCategory} axisLine={false} tickLine={false} />
<Recharts.YAxis domain={[0, 8]} tickFormatter={formatValue} axisLine={false} tickLine={false} width="auto" />
<Recharts.Area
dataKey="amount"
type="linear"
stroke="var(--color-amount)"
fill="var(--color-amount)"
fillOpacity={0.2}
isAnimationActive={false}
connectNulls={false}
/>
<ChartTooltip />
</Recharts.AreaChart>
</ChartContainer>
<ChartLegend config={config} label="Amount series" />
<section aria-label="Illustrative source values">
<DataTable columns={columns} rows={data} />
</section>
</div>
);
}
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| shared | boolean | undefined | – | Inspect all series at an axis position when true, or individual marks when false; unset follows the Recharts root's default. |
| config | ChartRegistry | undefined | – | The registry; inherited from ChartContainer when unset. |
| series | readonly string[] | undefined | – | Series in display order; inherited from ChartContainer when unset. |
| bands | readonly ChartBandDefinition[] | undefined | – | Intervals displayed under their associated series; inherited from ChartContainer when unset. |
| formatCategory | ((value: string | number) => string) | undefined | – | Writes the category or time with its reference; inherited from ChartContainer when unset. |
| missingValueText | string | undefined | – | Display text for a missing value; inherited from ChartContainer when unset. |
| testId | string | undefined | – | Becomes data-testid on the visible tooltip content. |
- Illustrative amount
Keep a gap and describe the missing measurement in the source table.
Related
- Data visualization: scales, missing measurements and comparable evidence.
- Chart panel: titles, controls and source information.
- Sparkline: compact trends with operational integrity and forecast information.