Compares a value across categories with bars from a zero baseline.
Before and after
Two states of one measure side by side, as figures or small charts, with the change between them stated in the middle.
- Use when
- A single measure at two moments or under two conditions: before and after a policy, control and treatment, last year and this. The change is computed from the two values unless you state it.
- Avoid when
- More than two states (use line chart or slope chart); many entities each with a before and after (use dumbbell chart or arrow chart); two unrelated figures (use stat row).
Preview
Solar module prices fell from $0.74 to $0.15 per watt between 2013 and 2023
Average price of crystalline silicon modules, US dollars per watt
Source: IRENA Renewable Power Generation Costs 2023 · Rounded, approximate figures for illustration
import { BeforeAfter } from "insightcharts";
export function Example() {
return (
<BeforeAfter
title="Solar module prices fell from $0.74 to $0.15 per watt between 2013 and 2023"
subtitle="Average price of crystalline silicon modules, US dollars per watt"
format={{ style: "currency", currency: "USD" }}
before={{ heading: "2013", value: 0.74, label: "Per watt", context: "2013 average" }}
after={{ heading: "2023", value: 0.15, label: "Per watt", context: "2023 average" }}
deltaLabel="in ten years"
upIsGood={false}
source="IRENA Renewable Power Generation Costs 2023"
note="Rounded, approximate figures for illustration"
/>
);
}{
"type": "before-after",
"title": "Solar module prices fell from $0.74 to $0.15 per watt between 2013 and 2023",
"subtitle": "Average price of crystalline silicon modules, US dollars per watt",
"format": { "style": "currency", "currency": "USD" },
"before": { "heading": "2013", "value": 0.74, "label": "Per watt", "context": "2013 average" },
"after": { "heading": "2023", "value": 0.15, "label": "Per watt", "context": "2023 average" },
"deltaLabel": "in ten years",
"upIsGood": false,
"source": "IRENA Renewable Power Generation Costs 2023",
"note": "Rounded, approximate figures for illustration"
}Render with import { Insight } from "insightcharts" and <Insight spec={spec} />. Nested specs resolve by name; nothing else to import.
Composition
Built from
The pieces before and after renders or expects in its slots.
Atoms
4A featured statistic with its label, change and the context that gives it meaning.
An inline change indicator: direction arrow, signed value and an optional baseline label.
A word-sized line or bar series without axes, with the latest point marked.
Used in
No template lists before and after in its composes. It still fits any slot that takes a component.
Installation
$ pnpm dlx shadcn@latest add @insightcharts/before-afterThe 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 { BeforeAfter } from "insightcharts";Examples
Two charts, change stated in words
The median midday price fell from €44 to €12 per MWh between summer 2019 and summer 2024
Median day-ahead price by hour, euros per MWh, same scale
Illustrative data
import { BeforeAfter, registerAll } from "insightcharts";
// The slot props below are JSON specs. This makes their `type` names resolvable.
registerAll();
export function Example() {
return (
<BeforeAfter
title="The median midday price fell from €44 to €12 per MWh between summer 2019 and summer 2024"
subtitle="Median day-ahead price by hour, euros per MWh, same scale"
before={{
heading: "Summer 2019",
chart: {
type: "bar-chart",
data: [
{ hour: "00:00", price: 38 },
{ hour: "03:00", price: 34 },
{ hour: "06:00", price: 41 },
{ hour: "09:00", price: 47 },
{ hour: "12:00", price: 44 },
{ hour: "15:00", price: 43 },
{ hour: "18:00", price: 52 },
{ hour: "21:00", price: 45 },
],
x: "hour",
y: "price",
orientation: "vertical",
sort: "none",
height: 150,
labels: false,
option: { yAxis: { max: 100 } },
},
}}
after={{
heading: "Summer 2024",
chart: {
type: "bar-chart",
data: [
{ hour: "00:00", price: 71 },
{ hour: "03:00", price: 64 },
{ hour: "06:00", price: 69 },
{ hour: "09:00", price: 48 },
{ hour: "12:00", price: 12 },
{ hour: "15:00", price: 21 },
{ hour: "18:00", price: 96 },
{ hour: "21:00", price: 84 },
],
x: "hour",
y: "price",
orientation: "vertical",
sort: "none",
height: 150,
labels: false,
option: { yAxis: { max: 100 } },
},
}}
delta="−€32"
deltaLabel="at midday"
upIsGood={false}
note="Illustrative data"
/>
);
}{
"type": "before-after",
"title": "The median midday price fell from €44 to €12 per MWh between summer 2019 and summer 2024",
"subtitle": "Median day-ahead price by hour, euros per MWh, same scale",
"before": {
"heading": "Summer 2019",
"chart": {
"type": "bar-chart",
"data": [
{ "hour": "00:00", "price": 38 },
{ "hour": "03:00", "price": 34 },
{ "hour": "06:00", "price": 41 },
{ "hour": "09:00", "price": 47 },
{ "hour": "12:00", "price": 44 },
{ "hour": "15:00", "price": 43 },
{ "hour": "18:00", "price": 52 },
{ "hour": "21:00", "price": 45 }
],
"x": "hour",
"y": "price",
"orientation": "vertical",
"sort": "none",
"height": 150,
"labels": false,
"option": { "yAxis": { "max": 100 } }
}
},
"after": {
"heading": "Summer 2024",
"chart": {
"type": "bar-chart",
"data": [
{ "hour": "00:00", "price": 71 },
{ "hour": "03:00", "price": 64 },
{ "hour": "06:00", "price": 69 },
{ "hour": "09:00", "price": 48 },
{ "hour": "12:00", "price": 12 },
{ "hour": "15:00", "price": 21 },
{ "hour": "18:00", "price": 96 },
{ "hour": "21:00", "price": 84 }
],
"x": "hour",
"y": "price",
"orientation": "vertical",
"sort": "none",
"height": 150,
"labels": false,
"option": { "yAxis": { "max": 100 } }
}
},
"delta": "−€32",
"deltaLabel": "at midday",
"upIsGood": false,
"note": "Illustrative data"
}Render with import { Insight } from "insightcharts" and <Insight spec={spec} />. Nested specs resolve by name; nothing else to import.
Figures with sparklines
import { BeforeAfter, registerAll } from "insightcharts";
// The slot props below are JSON specs. This makes their `type` names resolvable.
registerAll();
export function Example() {
return (
<BeforeAfter
before={{
heading: "Before the redesign",
value: 0.042,
format: "percent",
label: "Monthly churn",
chart: {
type: "sparkline",
data: [
{ v: 4.4 },
{ v: 4.1 },
{ v: 4.3 },
{ v: 4.2 },
{ v: 4.3 },
{ v: 4.2 },
],
y: "v",
},
}}
after={{
heading: "After",
value: 0.021,
format: "percent",
label: "Monthly churn",
chart: {
type: "sparkline",
data: [
{ v: 3.6 },
{ v: 3.1 },
{ v: 2.6 },
{ v: 2.4 },
{ v: 2.2 },
{ v: 2.1 },
],
y: "v",
},
}}
upIsGood={false}
deltaLabel="after six months"
/>
);
}{
"type": "before-after",
"before": {
"heading": "Before the redesign",
"value": 0.042,
"format": "percent",
"label": "Monthly churn",
"chart": {
"type": "sparkline",
"data": [
{ "v": 4.4 },
{ "v": 4.1 },
{ "v": 4.3 },
{ "v": 4.2 },
{ "v": 4.3 },
{ "v": 4.2 }
],
"y": "v"
}
},
"after": {
"heading": "After",
"value": 0.021,
"format": "percent",
"label": "Monthly churn",
"chart": {
"type": "sparkline",
"data": [
{ "v": 3.6 },
{ "v": 3.1 },
{ "v": 2.6 },
{ "v": 2.4 },
{ "v": 2.2 },
{ "v": 2.1 }
],
"y": "v"
}
},
"upIsGood": false,
"deltaLabel": "after six months"
}Render with import { Insight } from "insightcharts" and <Insight spec={spec} />. Nested specs resolve by name; nothing else to import.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| beforerequired | { heading?, value?, label?, context?, format?, chart? } | The first state: a figure, a chart slot, or both. | |
| afterrequired | { heading?, value?, label?, context?, format?, chart? } | The second state. | |
| delta | number | string | The change stated between the two. Default: the relative change when both values are numbers. | |
| deltaLabel | string | Words under the change, e.g. "in five years". | |
| deltaFormat | FormatSpec | signed percent | Number format for a numeric delta. |
| upIsGood | boolean | true | Whether an increase is good news; decides the colour of the change. |
| format | FormatSpec | "auto" | Number format shared by both values. |
| title | string | The change stated plainly, with both values and the period. | |
| subtitle | string | Measure and population. | |
| source | string | Shown underneath as "Source: ...". | |
| note | string | Method note or caveat. | |
| theme | ThemeInput | Theme override, passed on to both states. | |
| mode | "auto" | "system" | "light" | "dark" | "auto" | Colour mode. |