Optimized for Dark Mode

The website is optimized for dark mode to enhance your user experience. Switch to dark mode to enjoy it.

Streamdown Recharts

A Streamdown custom renderer that turns recharts-json code fences from an LLM stream into live, interactive charts — with table view and CSV/XLSX/PNG export.


Large language models are great at producing structured JSON, but turning that JSON into a chart usually means shipping a brittle eval or a heavy client bundle. Streamdown Recharts takes a different route: the model emits a fenced recharts-json block, and a Streamdown custom renderer parses it, validates it with Zod, and renders a Recharts chart — streaming-aware, so you get a loading skeleton until the fence closes.

EBIT by Fiscal Year

Reported vs. Adjusted EBIT (in € millions).

It handles bar, line, area, pie and scatter charts, falls back gracefully on incomplete or malformed JSON, and ships a table view plus one-click exports.

Installation

Shell
npx shadcn@latest add https://bitbasti.com/r/streamdown-recharts.json

Then register the renderer on your Streamdown instance via the renderers plugin slot. This is the minimal wiring you need:

React
import { Streamdown } from "streamdown";
import { rechartsRenderers } from "@/components/streamdown-recharts";
 
export function Message({ markdown }: { markdown: string }) {
  return (
    <Streamdown plugins={{ renderers: rechartsRenderers }}>
      {markdown}
    </Streamdown>
  );
}

rechartsRenderers is a CustomRenderer[] that maps the recharts-json (and rechart-json) code-fence languages to the chart component. You can combine it with Streamdown's other plugins (code, math, mermaid, cjk) in the same object:

React
<Streamdown
  plugins={{
    code,
    math,
    mermaid,
    renderers: rechartsRenderers,
  }}
>
  {markdown}
</Streamdown>

Usage

Anywhere in the model's markdown, a fenced recharts-json block is upgraded to a chart:

Markdown
```recharts-json
{
  "chartType": "line",
  "xKey": "month",
  "series": [{ "dataKey": "visitors", "label": "Visitors" }],
  "data": [
    { "month": "Jan", "visitors": 5000 },
    { "month": "Feb", "visitors": 6200 }
  ]
}
```

While the fence is still streaming, Streamdown reports the block as incomplete and the renderer shows a skeleton instead of flashing a parse error. Once the closing fence arrives, the JSON is parsed and validated in one pass.

Prompting the model

To get the model to emit charts, teach it the fence in your system prompt and let it decide when a chart helps. A compact system prompt:

Text
You are a data analyst assistant. When the user asks for a chart, or when
tabular numbers would be clearer as a visualization, respond with a fenced
`recharts-json` code block.
 
The JSON must match this shape:
- chartType: "bar" | "line" | "area" | "pie" | "scatter"
- xKey: string (the category/value axis key; omit for pie)
- series: array of { dataKey, label } (one entry per plotted value)
- data: array of row objects keyed by xKey and each series dataKey
- nameKey / valueKey: strings (pie charts only)
- meta: { title, description } for the chart header
 
Emit only valid JSON inside the fence — no comments or trailing commas. Use
null for missing data points. Add a short sentence of context before the chart.

A sample user prompt:

Text
Plot our quarterly revenue and costs for last year:
Q1 revenue 120k / costs 90k, Q2 185k / 120k, Q3 240k / 150k, Q4 310k / 190k.
Use an area chart in US dollars.

The model replies with prose plus a recharts-json fence, which the renderer upgrades into the live chart above.

Examples

Line

Multiple series share a single x-axis. String x-values render as categories, numeric ones as a continuous axis.

Website Traffic

Monthly traffic trend.

Area

Stack several series to compare trends — here, two filled areas on a shared axis.

Quarterly Revenue vs Costs

Revenue and costs by quarter.

Pie

Pie charts are driven by nameKey (slice label) and valueKey (slice size).

Deployment Mix

Share by deployment model.

Scatter

The x-axis key is inferred from the data when xKey is omitted, and the axis type adapts to whether the values are numeric.

Ad Spend vs Sales

Advertising investment against sales revenue.

Schema

Every spec is validated against a Zod schema before it renders. Invalid specs show the raw JSON with an inline error rather than crashing the page.

FieldTypeRequiredNotes
chartType"bar" | "line" | "area" | "pie" | "scatter"yesSelects the visualization.
series{ dataKey, label?, valueFormat?, ... }[]yesAt least one series.
dataRecord<string, string | number | null>[]yesnull renders as a gap.
xKeystringnoCategory/value axis key. Inferred for scatter.
nameKeystringnoPie slice label key.
valueKeystringnoPie slice value key.
layout"horizontal" | "vertical"noBar charts only.
localestringnoNumber/tick formatting, e.g. de-DE.
currencystringnoISO currency for valueFormat: "currency".
meta{ title?, description? }noHeader above the chart and export file name.

Beyond the chart

Each rendered chart carries a small toolbar:

  • Table view — toggle from chart to a formatted data table.
  • Export — download the data as CSV or XLSX, or the chart as a PNG.

Number formatting respects the spec's locale and currency, so the same data reads naturally whether you are in en-US or de-DE.