Compares a value across categories with bars from a zero baseline.
Chart with callout
A chart with a callout beside it that states the main fact. In narrow containers the callout goes underneath.
- Use when
- Whenever a chart needs its meaning stated in words next to it: the standard chart-plus-interpretation unit of a report. The chart's title states the main fact with its number. The callout adds a second fact, a cause or a caveat in plain words.
- Avoid when
- Repeating the chart title in the callout; long narration (put prose before the chart instead); a chart that is already a small tile (the callout would outweigh it).
Preview
Monthly churn fell from 4.2% to 2.1% in 2024
Monthly customer churn, 2024
import { ChartCallout, registerAll } from "insightcharts";
// The slot props below are JSON specs. This makes their `type` names resolvable.
registerAll();
export function Example() {
return (
<ChartCallout
chart={{
type: "line-chart",
data: [
{ month: "2024-01-01", rate: 4.2 },
{ month: "2024-02-01", rate: 4.3 },
{ month: "2024-03-01", rate: 4.1 },
{ month: "2024-04-01", rate: 3.6 },
{ month: "2024-05-01", rate: 3.1 },
{ month: "2024-06-01", rate: 2.9 },
{ month: "2024-07-01", rate: 2.6 },
{ month: "2024-08-01", rate: 2.4 },
{ month: "2024-09-01", rate: 2.3 },
{ month: "2024-10-01", rate: 2.2 },
{ month: "2024-11-01", rate: 2.1 },
{ month: "2024-12-01", rate: 2.1 },
],
x: "month",
y: "rate",
format: "{value}%",
zero: true,
height: 280,
title: "Monthly churn fell from 4.2% to 2.1% in 2024",
subtitle: "Monthly customer churn, 2024",
source: "Internal analytics",
note: "Illustrative data",
annotations: [
{ type: "line", axis: "x", value: "2024-03-01", label: "New onboarding" },
],
}}
label="Takeaway"
lead="Churn fell 2 points after March"
body="Churn was 4.1% in March, when the new onboarding launched. It fell every month from April to November. It was 2.1% in December."
/>
);
}{
"type": "chart-callout",
"chart": {
"type": "line-chart",
"data": [
{ "month": "2024-01-01", "rate": 4.2 },
{ "month": "2024-02-01", "rate": 4.3 },
{ "month": "2024-03-01", "rate": 4.1 },
{ "month": "2024-04-01", "rate": 3.6 },
{ "month": "2024-05-01", "rate": 3.1 },
{ "month": "2024-06-01", "rate": 2.9 },
{ "month": "2024-07-01", "rate": 2.6 },
{ "month": "2024-08-01", "rate": 2.4 },
{ "month": "2024-09-01", "rate": 2.3 },
{ "month": "2024-10-01", "rate": 2.2 },
{ "month": "2024-11-01", "rate": 2.1 },
{ "month": "2024-12-01", "rate": 2.1 }
],
"x": "month",
"y": "rate",
"format": "{value}%",
"zero": true,
"height": 280,
"title": "Monthly churn fell from 4.2% to 2.1% in 2024",
"subtitle": "Monthly customer churn, 2024",
"source": "Internal analytics",
"note": "Illustrative data",
"annotations": [
{ "type": "line", "axis": "x", "value": "2024-03-01", "label": "New onboarding" }
]
},
"label": "Takeaway",
"lead": "Churn fell 2 points after March",
"body": "Churn was 4.1% in March, when the new onboarding launched. It fell every month from April to November. It was 2.1% in December."
}Render with import { Insight } from "insightcharts" and <Insight spec={spec} />. Nested specs resolve by name; nothing else to import.
Composition
Built from
The pieces chart with callout renders or expects in its slots.
Atoms
3A boxed statement of fact with a short bold lead and a sentence of explanation. The tone is marked by icon and tint.
Shows how one or more values change over time or another ordered dimension.
Used in
2 templates use chart with callout.
Templates
2A one-page summary. It has a headline that states the main finding with its number, a deck, a row of three or four key figures, one hero chart with a takeaway callout, two smaller supporting exhibits, a short list of actions and a source note.
A long article read by scrolling. It has a headline, then an ordered list of blocks in a reading column, then a source note. The blocks are prose, figures, charts with a callout, scrolly sequences, pull quotes, stat rows, small multiples and chapter breaks. Exhibits can be wider than the column.
Installation
$ pnpm dlx shadcn@latest add @insightcharts/chart-calloutThe CLI copies the source into your project and needs the @insightcharts registry in components.json; see installation. With the package, import it by name:
import { ChartCallout } from "insightcharts";Examples
Caveat on the left, boxed
Monthly churn fell from 4.1% in March to 2.9% in June 2024
Monthly customer churn, January to June 2024
import { ChartCallout, registerAll } from "insightcharts";
// The slot props below are JSON specs. This makes their `type` names resolvable.
registerAll();
export function Example() {
return (
<ChartCallout
side="left"
variant="soft"
tone="negative"
label="Caveat"
lead="The new onboarding launched on 11 March"
body="The March figure includes customers who joined before the launch. April is the first full month on the new onboarding."
chart={{
type: "bar-chart",
data: [
{ month: "Jan", rate: 4.2 },
{ month: "Feb", rate: 4.3 },
{ month: "Mar", rate: 4.1 },
{ month: "Apr", rate: 3.6 },
{ month: "May", rate: 3.1 },
{ month: "Jun", rate: 2.9 },
],
x: "month",
sort: "none",
y: "rate",
format: "{value}%",
orientation: "vertical",
height: 260,
title: "Monthly churn fell from 4.1% in March to 2.9% in June 2024",
subtitle: "Monthly customer churn, January to June 2024",
}}
/>
);
}{
"type": "chart-callout",
"side": "left",
"variant": "soft",
"tone": "negative",
"label": "Caveat",
"lead": "The new onboarding launched on 11 March",
"body": "The March figure includes customers who joined before the launch. April is the first full month on the new onboarding.",
"chart": {
"type": "bar-chart",
"data": [
{ "month": "Jan", "rate": 4.2 },
{ "month": "Feb", "rate": 4.3 },
{ "month": "Mar", "rate": 4.1 },
{ "month": "Apr", "rate": 3.6 },
{ "month": "May", "rate": 3.1 },
{ "month": "Jun", "rate": 2.9 }
],
"x": "month",
"sort": "none",
"y": "rate",
"format": "{value}%",
"orientation": "vertical",
"height": 260,
"title": "Monthly churn fell from 4.1% in March to 2.9% in June 2024",
"subtitle": "Monthly customer churn, January to June 2024"
}
}Render with import { Insight } from "insightcharts" and <Insight spec={spec} />. Nested specs resolve by name; nothing else to import.
Positive, aligned to the top
Monthly churn was 2.1% in December 2024
Monthly customer churn, 2024
import { ChartCallout, registerAll } from "insightcharts";
// The slot props below are JSON specs. This makes their `type` names resolvable.
registerAll();
export function Example() {
return (
<ChartCallout
tone="positive"
align="start"
lead="Churn stayed below 2.5% from August"
body="Monthly churn was between 2.1% and 2.4% from August to December 2024."
chart={{
type: "line-chart",
data: [
{ month: "2024-01-01", rate: 4.2 },
{ month: "2024-02-01", rate: 4.3 },
{ month: "2024-03-01", rate: 4.1 },
{ month: "2024-04-01", rate: 3.6 },
{ month: "2024-05-01", rate: 3.1 },
{ month: "2024-06-01", rate: 2.9 },
{ month: "2024-07-01", rate: 2.6 },
{ month: "2024-08-01", rate: 2.4 },
{ month: "2024-09-01", rate: 2.3 },
{ month: "2024-10-01", rate: 2.2 },
{ month: "2024-11-01", rate: 2.1 },
{ month: "2024-12-01", rate: 2.1 },
],
x: "month",
y: "rate",
format: "{value}%",
zero: true,
height: 240,
title: "Monthly churn was 2.1% in December 2024",
subtitle: "Monthly customer churn, 2024",
}}
/>
);
}{
"type": "chart-callout",
"tone": "positive",
"align": "start",
"lead": "Churn stayed below 2.5% from August",
"body": "Monthly churn was between 2.1% and 2.4% from August to December 2024.",
"chart": {
"type": "line-chart",
"data": [
{ "month": "2024-01-01", "rate": 4.2 },
{ "month": "2024-02-01", "rate": 4.3 },
{ "month": "2024-03-01", "rate": 4.1 },
{ "month": "2024-04-01", "rate": 3.6 },
{ "month": "2024-05-01", "rate": 3.1 },
{ "month": "2024-06-01", "rate": 2.9 },
{ "month": "2024-07-01", "rate": 2.6 },
{ "month": "2024-08-01", "rate": 2.4 },
{ "month": "2024-09-01", "rate": 2.3 },
{ "month": "2024-10-01", "rate": 2.2 },
{ "month": "2024-11-01", "rate": 2.1 },
{ "month": "2024-12-01", "rate": 2.1 }
],
"x": "month",
"y": "rate",
"format": "{value}%",
"zero": true,
"height": 240,
"title": "Monthly churn was 2.1% in December 2024",
"subtitle": "Monthly customer churn, 2024"
}
}Render with import { Insight } from "insightcharts" and <Insight spec={spec} />. Nested specs resolve by name; nothing else to import.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| chartrequired | Slot | The chart: a spec or a React element. | |
| lead | string | The main fact in a few words, with its number. Shown in bold. | |
| body | string | One or two plain sentences that say what the fact means. | |
| tone | "neutral" | "positive" | "negative" | "accent" | "accent" | Sets the callout's icon and tint together. |
| label | string | Small label above the lead, e.g. "Takeaway" or "Caveat". | |
| side | "left" | "right" | "right" | Side of the chart the callout sits on. Under 640px it always goes underneath. |
| variant | "plain" | "soft" | "outline" | "plain" | plain separates the callout with a hairline; the others box it. |
| align | "start" | "center" | "end" | "center" | Vertical position of the callout beside the chart. |
| children | ReactNode | JSX alternative to chart. | |
| theme | ThemeInput | Theme override, passed on to the chart and callout. | |
| mode | "auto" | "system" | "light" | "dark" | "auto" | Colour mode. |