A poster that counts at scale. Blocks of thousands of unit icons fill most of the sheet, a second band counts reference groups with the same icon at the same size in a muted colour, and a bottom row holds three small graphics: squares sized by area with a ratio bracket, thick bars with the numbers inside, and shares as nested outlines or filled silhouettes.
Shape fill
Shows one or more percentages as icon silhouettes filled from the bottom to that level, with the number printed large beside each.
- Use when
- One to six shares of a full amount where the object itself says what is measured: how full a reservoir is, how charged a fleet is, what share of homes have a heat pump.
- Avoid when
- The fill height only approximates the share, because an irregular silhouette holds less area at its narrow end, so the number must always stay printed; for values to be compared precisely use block bars or bar chart, for a counted share use waffle chart, for a compact inline meter use progress meter.
Preview
import { ShapeFill } from "insightcharts";
const data = [
{ reservoir: "Carrow", level: 63 },
{ reservoir: "Upper Fen", level: 41 },
{ reservoir: "Stonebeck", level: 88 },
];
export function Example() {
return (
<ShapeFill
data={data}
name="reservoir"
value="level"
icon="drop"
format={"{value}%"}
title="Carrow Reservoir was 63% full on 1 September 2025"
subtitle="Water stored as a share of capacity, three reservoirs, 1 September 2025"
source="Illustrative data"
note="Invented figures for fictional reservoirs"
/>
);
}{
"type": "shape-fill",
"data": [
{ "reservoir": "Carrow", "level": 63 },
{ "reservoir": "Upper Fen", "level": 41 },
{ "reservoir": "Stonebeck", "level": 88 }
],
"name": "reservoir",
"value": "level",
"icon": "drop",
"format": "{value}%",
"title": "Carrow Reservoir was 63% full on 1 September 2025",
"subtitle": "Water stored as a share of capacity, three reservoirs, 1 September 2025",
"source": "Illustrative data",
"note": "Invented figures for fictional reservoirs"
}Render with import { Insight } from "insightcharts" and <Insight spec={spec} />. Nested specs resolve by name; nothing else to import.
Composition
Used in
3 infographics use shape fill.
Infographics
3A poster that describes one subject from four sides: the subject as one large silhouette filled to a share (shape-fill), two to four large figures, its place among other things on one scale (scale-ladder), and a table that sets it beside its peers with every number drawn as a small form (glyph-table).
A poster of one subject by the numbers, in four rows: two figures in large type or as filled silhouettes, two treemaps side by side, a full-width ranking of centred pills with one row highlighted, and packed circles with icons beside a column of sized circles and a closing figure.
Installation
$ pnpm dlx shadcn@latest add @insightcharts/shape-fillThe 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 { ShapeFill } from "insightcharts";Examples
One silhouette
import { ShapeFill } from "insightcharts";
export function Example() {
return (
<ShapeFill
data={[
{ what: "of homes in Eastvale had a heat pump", share: 0.18 },
]}
name="what"
value="share"
icon="house"
format="percent"
title="18% of homes in Eastvale had a heat pump in 2025"
subtitle="Share of occupied homes with a heat pump installed, 2025"
source="Illustrative data"
note="Invented figure for a fictional town"
/>
);
}{
"type": "shape-fill",
"data": [
{ "what": "of homes in Eastvale had a heat pump", "share": 0.18 }
],
"name": "what",
"value": "share",
"icon": "house",
"format": "percent",
"title": "18% of homes in Eastvale had a heat pump in 2025",
"subtitle": "Share of occupied homes with a heat pump installed, 2025",
"source": "Illustrative data",
"note": "Invented figure for a fictional town"
}Render with import { Insight } from "insightcharts" and <Insight spec={spec} />. Nested specs resolve by name; nothing else to import.
One silhouette sized by the height prop
import { ShapeFill } from "insightcharts";
export function Example() {
return (
<ShapeFill
data={[
{ what: "of the battery fleet was charged at 6am", share: 0.72 },
]}
name="what"
value="share"
icon="bolt"
format="percent"
height={460}
title="72% of the battery fleet was charged at 6am on 3 March 2025"
subtitle="Share of 140 electric buses with a full charge at the start of service"
source="Illustrative data"
note="Invented figure for a fictional operator"
/>
);
}{
"type": "shape-fill",
"data": [
{ "what": "of the battery fleet was charged at 6am", "share": 0.72 }
],
"name": "what",
"value": "share",
"icon": "bolt",
"format": "percent",
"height": 460,
"title": "72% of the battery fleet was charged at 6am on 3 March 2025",
"subtitle": "Share of 140 electric buses with a full charge at the start of service",
"source": "Illustrative data",
"note": "Invented figure for a fictional operator"
}Render with import { Insight } from "insightcharts" and <Insight spec={spec} />. Nested specs resolve by name; nothing else to import.
Highlight, click to select
import { ShapeFill } from "insightcharts";
const data = [
{ district: "Northbank", cover: 34 },
{ district: "Old Town", cover: 9 },
{ district: "Riverside", cover: 22 },
{ district: "Hillcrest", cover: 47 },
];
export function Example() {
return (
<ShapeFill
data={data}
name="district"
value="cover"
icon="tree"
format={"{value}%"}
highlight="Old Town"
select
title="Trees covered 9% of Old Town in 2025"
subtitle="Tree canopy as a share of land area by district, 2025"
source="Illustrative data"
note="Invented figures for a fictional city"
/>
);
}{
"type": "shape-fill",
"data": [
{ "district": "Northbank", "cover": 34 },
{ "district": "Old Town", "cover": 9 },
{ "district": "Riverside", "cover": 22 },
{ "district": "Hillcrest", "cover": 47 }
],
"name": "district",
"value": "cover",
"icon": "tree",
"format": "{value}%",
"highlight": "Old Town",
"select": true,
"title": "Trees covered 9% of Old Town in 2025",
"subtitle": "Tree canopy as a share of land area by district, 2025",
"source": "Illustrative data",
"note": "Invented figures for a fictional city"
}Render with import { Insight } from "insightcharts" and <Insight spec={spec} />. Nested specs resolve by name; nothing else to import.
Stress: six items, mixed icons, long labels
import { ShapeFill } from "insightcharts";
const data = [
{ item: "Electric buses charged and ready at 6am", ready: 92 },
{ item: "Households on a time-of-use electricity tariff", ready: 27 },
{ item: "Company cars that are battery electric", ready: 54 },
{ item: "Street trees surviving their first five years", ready: 71 },
{ item: "Reservoir storage", ready: 3 },
{ item: "Adults with a savings account", ready: 100 },
];
export function Example() {
return (
<ShapeFill
data={data}
name="item"
value="ready"
icons={{
"Electric buses charged and ready at 6am": "bolt",
"Households on a time-of-use electricity tariff": "house",
"Company cars that are battery electric": "car",
"Street trees surviving their first five years": "tree",
"Reservoir storage": "drop",
"Adults with a savings account": "person",
}}
columns={3}
colorBy="item"
format={"{value}%"}
title="Six shares from the 2025 city report"
subtitle="Each silhouette is filled to the share shown beside it"
source="Illustrative data"
note="Invented figures"
/>
);
}{
"type": "shape-fill",
"data": [
{ "item": "Electric buses charged and ready at 6am", "ready": 92 },
{ "item": "Households on a time-of-use electricity tariff", "ready": 27 },
{ "item": "Company cars that are battery electric", "ready": 54 },
{ "item": "Street trees surviving their first five years", "ready": 71 },
{ "item": "Reservoir storage", "ready": 3 },
{ "item": "Adults with a savings account", "ready": 100 }
],
"name": "item",
"value": "ready",
"icons": {
"Electric buses charged and ready at 6am": "bolt",
"Households on a time-of-use electricity tariff": "house",
"Company cars that are battery electric": "car",
"Street trees surviving their first five years": "tree",
"Reservoir storage": "drop",
"Adults with a savings account": "person"
},
"columns": 3,
"colorBy": "item",
"format": "{value}%",
"title": "Six shares from the 2025 city report",
"subtitle": "Each silhouette is filled to the share shown beside it",
"source": "Illustrative data",
"note": "Invented figures"
}Render with import { Insight } from "insightcharts" and <Insight spec={spec} />. Nested specs resolve by name; nothing else to import.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| namerequired | string | Label field: one silhouette per row. | |
| valuerequired | string | Value field: how full each silhouette is, against max. | |
| max | number | The value that fills a silhouette completely. Default: 1 when every value is at most 1, otherwise 100. | |
| icon | IconName | "path://..." | "drop" | Built-in icon name or a custom single SVG path. |
| icons | Record<string, string> | Icon per label; falls back to icon. | |
| columns | number | Silhouettes per line. Default: up to four, two on a phone. | |
| colorBy | "single" | "item" | "single" | single: every silhouette in the accent colour. item: one colour per row. |
| iconSize | number | Silhouette height in px. Default: sized to the width, or grown to fill the box when the height prop or aspect is given, so one silhouette can be the main figure of a poster. |
Common chart props 29
Every chart built with defineChart accepts these on top of its own props.
| Prop | Type | Description |
|---|---|---|
| data | DataInput | Rows, CSV text, a URL, { url, path }, an async function, or an Arrow-style table. Omit inside <InsightData>. |
| transform | Transform | Transform[] | A pipeline of transforms applied before drawing. |
| title | string | The title. One plain statement of what the data shows, with the number and the period ("Monthly churn fell from 4.2% to 2.1% in 2024"), or a plain label ("Monthly churn, 2024"). One clause, no figures of speech. |
| subtitle | string | Measure, unit, population, period. |
| source | string | Data source, shown as "Source: ...". |
| note | string | Method notes or caveats. |
| height | number | string | CSS height of the plot. Default 360. |
| aspect | number | Width / height. Overrides height. |
| highlight | string | string[] | The entity (or entities) the title is about. Every other series is drawn in grey. |
| annotations | Annotation[] | Reference lines, shaded bands and callouts, in data coordinates. |
| format | FormatSpec | How to print values: "compact", "percent", "currency:USD", "{value} kg", Intl options, or a function. |
| legend | boolean | Show the legend. Default: shown when there are two or more series. |
| select | boolean | string | Make marks clickable to filter. Inside <InsightData> the selection filters every other chart. Pass a field name, or true to use the chart's category field. |
| onSelect | (values: string[], field: string) => void | Called with the selected values whenever the selection changes. |
| option | EChartsOption | ((option: EChartsOption, ctx: BuildContext) => EChartsOption) | Deep-merged over the generated ECharts option, or a function that receives and returns it. Use it for ECharts settings no prop covers. |
| theme | ThemeInput | A theme, or a partial set of tokens merged over the surrounding theme, for this chart only. |
| mode | ModeInput | "auto" (default) follows the page, "system" follows the OS, or force "light" / "dark". |
| renderer | RendererInput | "auto" (default) uses SVG for light charts and canvas for heavy ones. |
| animate | boolean | Set false to disable animation. Reduced-motion preferences are always respected. |
| lazy | boolean | Mount the chart only when it scrolls near the viewport. Default true. |
| group | string | Link tooltips with other charts sharing this group id. |
| exportable | boolean | ExportFormat[] | Show an export menu: true or a list of formats from png, jpeg, svg, pdf, csv, json. |
| table | boolean | Show a collapsible "View data" table under the chart. |
| alt | string | Accessible description: the chart type and measures, then the main pattern and the notable values. |
| id | string | Stable id for this chart's selection in the shared store. |
| onEvents | Record<string, ChartEventHandler> | ECharts event handlers, e.g. { click: (params, chart) => {} }. Prefix a name with zr: to bind to the canvas itself. |
| onReady | (chart: EChartsInstance) => void | Called with the ECharts instance once it is created. |
| className | string | Class name for the outer <figure>. |
| style | CSSProperties | Inline style for the outer <figure>. |