A story section: a numbered step marker or a headline, introductory prose, then one or more exhibits in a responsive one- to three-column grid.
Stat tile
A compact, bordered KPI tile: label, value, change against a baseline and an optional trend graphic.
- Use when
- Dashboard grids and KPI rows of three to six figures, each needing its own change indicator or sparkline. Give every tile a delta or a context line.
- Avoid when
- The single number a story leads with (use big number with
size: "hero"). Do not put a full chart with axes in the trend slot.
Preview
import { StatTile } from "insightcharts";
export function Example() {
return (
<StatTile
label="Monthly active users"
value={48210}
format="compact"
delta={0.083}
deltaLabel="vs September"
trend={[38.1, 39.4, 39, 40.8, 42.2, 41.9, 43.5, 44.1, 44.5, 46, 47.2, 48.2]}
style={{ maxWidth: 300 }}
/>
);
}{
"type": "stat-tile",
"label": "Monthly active users",
"value": 48210,
"format": "compact",
"delta": 0.083,
"deltaLabel": "vs September",
"trend": [38.1, 39.4, 39, 40.8, 42.2, 41.9, 43.5, 44.1, 44.5, 46, 47.2, 48.2],
"style": { "maxWidth": 300 }
}Render with import { Insight } from "insightcharts" and <Insight spec={spec} />. Nested specs resolve by name; nothing else to import.
Composition
Used in
3 molecules and 3 templates use stat tile.
Molecules
3Two to five key figures in one row separated by hairlines, collapsing to two columns and then one as the container narrows.
A KPI card computed from a series: the latest value, its change against a baseline in the same data, and a sparkline of the series.
Templates
3A set of linked charts over one shared dataset that filter each other. It has a headline, a sentence of instructions with filter chips, a row of figures that recompute from the filtered rows, two to four charts and an optional detail table. It opens on selections the author chooses.
A 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/stat-tileThe 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 { StatTile } from "insightcharts";Examples
Down is good, trend on the right
import { StatTile } from "insightcharts";
export function Example() {
return (
<StatTile
label="Median first-response time"
value="2 h 14 min"
delta={-0.18}
deltaLabel="vs last quarter"
upIsGood={false}
trend={[4.1, 3.9, 3.8, 3.2, 3.4, 2.9, 2.7, 2.4, 2.2]}
trendPosition="right"
style={{ maxWidth: 420 }}
/>
);
}{
"type": "stat-tile",
"label": "Median first-response time",
"value": "2 h 14 min",
"delta": -0.18,
"deltaLabel": "vs last quarter",
"upIsGood": false,
"trend": [4.1, 3.9, 3.8, 3.2, 3.4, 2.9, 2.7, 2.4, 2.2],
"trendPosition": "right",
"style": { "maxWidth": 420 }
}Render with import { Insight } from "insightcharts" and <Insight spec={spec} />. Nested specs resolve by name; nothing else to import.
Context only
import { StatTile } from "insightcharts";
export function Example() {
return (
<StatTile
label="Net revenue retention"
value={1.12}
format="percent"
context="Top quartile for the sector is 110%."
style={{ maxWidth: 260 }}
/>
);
}{
"type": "stat-tile",
"label": "Net revenue retention",
"value": 1.12,
"format": "percent",
"context": "Top quartile for the sector is 110%.",
"style": { "maxWidth": 260 }
}Render with import { Insight } from "insightcharts" and <Insight spec={spec} />. Nested specs resolve by name; nothing else to import.
Chart spec in the trend slot
import { StatTile, registerAll } from "insightcharts";
// The slot props below are JSON specs. This makes their `type` names resolvable.
registerAll();
export function Example() {
return (
<StatTile
label="Solar share of generation"
value={0.113}
format="percent"
delta="+1.9 pts"
deltaLabel="vs 2023"
trend={{
type: "big-number",
label: "Peak hour, 14 July",
value: 0.52,
format: "percent",
context: "Any registered component can sit here.",
}}
style={{ maxWidth: 300 }}
/>
);
}{
"type": "stat-tile",
"label": "Solar share of generation",
"value": 0.113,
"format": "percent",
"delta": "+1.9 pts",
"deltaLabel": "vs 2023",
"trend": {
"type": "big-number",
"label": "Peak hour, 14 July",
"value": 0.52,
"format": "percent",
"context": "Any registered component can sit here."
},
"style": { "maxWidth": 300 }
}Render with import { Insight } from "insightcharts" and <Insight spec={spec} />. Nested specs resolve by name; nothing else to import.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| labelrequired | string | What it measures, sentence case. | |
| valuerequired | number | string | The figure. Numbers are formatted with format. | |
| delta | number | string | Change against a baseline. Numbers render as signed percentages (0.12 is +12%). | |
| deltaLabel | string | What the delta is against, e.g. "vs last month". | |
| upIsGood | boolean | true | Whether an increase is an improvement. Sets the delta colour. |
| context | string | A line that states a comparison or reference for the number. | |
| trend | Slot | number[] | A chart spec, a React element, or an array of numbers drawn as a sparkline. | |
| trendPosition | "bottom" | "right" | "bottom" | Where the trend sits; right falls back to bottom under 280px. |
| format | FormatSpec | "auto" | Number format for value. |
| children | ReactNode | Extra content at the bottom of the tile. |