← Back to blog

Engine-native charts: BarChart, LineChart, PieChart, AreaChart, and DotPlot

Charts are now rendered directly by the Rust engine as PDF vector graphics. Five chart types, multi-series support, and zero external dependencies.

Forme 0.7.13 moves chart rendering from the React layer into the Rust engine. Instead of generating intermediate SVG that the engine then converts to PDF drawing commands, charts now produce native PDF vector primitives directly. The result is the same crisp output with less overhead and more control.

What changed

Previously, <BarChart>, <LineChart>, and <PieChart> were React components that returned <View> + <Svg> + positioned <Text> children. The engine saw generic nodes and converted SVG shapes to PDF. That worked, but it meant chart logic lived in JavaScript, added node tree overhead, and couldn't take advantage of engine-level optimizations.

Now, the engine has five first-class NodeKind variants: BarChart, LineChart, PieChart, AreaChart, and DotPlot. Each chart type has a dedicated builder module in Rust that computes geometry and emits a flat list of drawing primitives — rectangles, lines, polylines, filled paths, circles, arc sectors, and text labels. The PDF renderer iterates these primitives and writes them directly to content streams.

Five chart types

BarChart

Category bar chart with optional grid lines, value labels, and a title.

import { BarChart } from '@formepdf/react';

<BarChart
  width={400}
  height={200}
  data={[
    { label: 'Q1', value: 142000 },
    { label: 'Q2', value: 186000 },
    { label: 'Q3', value: 164000 },
    { label: 'Q4', value: 228000 },
  ]}
  color="#3b82f6"
  showGrid
  showValues
  title="Quarterly Revenue"
/>

LineChart

Multi-series line chart. Pass an array of series, each with its own name, data, and color.

import { LineChart } from '@formepdf/react';

<LineChart
  width={500}
  height={200}
  series={[
    { name: 'Active Users', data: [1200, 1800, 2400, 3100, 3800, 4200], color: '#3b82f6' },
    { name: 'New Signups', data: [400, 600, 800, 900, 1100, 1000], color: '#10b981' },
  ]}
  labels={['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun']}
  showPoints
  showGrid
  title="User Growth"
/>

Note the API change: LineChart now takes series and labels instead of the old data + color props. This enables multiple lines with distinct colors in a single chart.

PieChart

Pie or donut chart with an optional legend.

import { PieChart } from '@formepdf/react';

<PieChart
  width={200}
  height={200}
  data={[
    { label: 'Subscriptions', value: 62, color: '#3b82f6' },
    { label: 'Enterprise', value: 28, color: '#0f172a' },
    { label: 'Services', value: 10, color: '#94a3b8' },
  ]}
  donut
  showLegend
/>

The donut boolean replaces the old innerRadius prop. The showLegend prop replaces showLabels.

AreaChart (new)

Like LineChart but with semi-transparent fill under each line. Useful for showing cumulative trends.

import { AreaChart } from '@formepdf/react';

<AreaChart
  width={500}
  height={200}
  series={[
    { name: 'Organic', data: [500, 800, 1200, 1800, 2600, 3200], color: '#3b82f6' },
    { name: 'Paid', data: [200, 400, 600, 900, 1100, 1400], color: '#f59e0b' },
  ]}
  labels={['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun']}
  showGrid
  title="Traffic Sources"
/>

DotPlot (new)

Scatter plot for (x, y) data points grouped by category. Good for comparing distributions or performance metrics across versions.

import { DotPlot } from '@formepdf/react';

<DotPlot
  width={300}
  height={200}
  groups={[
    { name: 'API v1', color: '#3b82f6', data: [[10, 45], [50, 120], [100, 230]] },
    { name: 'API v2', color: '#10b981', data: [[10, 25], [50, 60], [100, 110]] },
  ]}
  xLabel="Concurrent Requests"
  yLabel="Latency (ms)"
  showLegend
  dotSize={3.5}
/>

How it works under the hood

Each chart component in @formepdf/react is an intrinsic element — it returns null during React rendering and is serialized directly to the engine's JSON format. The Rust engine receives the chart node, calls the appropriate builder, and gets back a Vec<ChartPrimitive>:

pub enum ChartPrimitive {
    Rect { x, y, w, h, fill },
    Line { x1, y1, x2, y2, stroke, width },
    Polyline { points, stroke, width },
    FilledPath { points, fill, opacity },
    Circle { cx, cy, r, fill },
    ArcSector { cx, cy, r, start_angle, end_angle, fill },
    Label { text, x, y, font_size, color, anchor },
}

The PDF renderer iterates this list inside a coordinate transform that flips Y (PDF uses bottom-left origin; charts use top-left). Each primitive maps to a few PDF operators: re f for rectangles, m l S for lines, cubic beziers for arcs and circles, BT/Tf/Td/Tj/ET for labels. Labels use Helvetica, which is always available in the engine's font system.

Migration from 0.7.12

If you're using the old chart API, here's what changed:

Old prop New prop Component
data (on LineChart) series + labels LineChart
color (on LineChart) per-series color LineChart
showDots showPoints LineChart
showArea use <AreaChart>
innerRadius donut (boolean) PieChart
showLabels showLegend PieChart
barGap removed (auto-computed) BarChart
yAxisTicks removed (auto-computed) BarChart, LineChart

The old SVG-based implementations are still available as LegacyBarChart, LegacyLineChart, and LegacyPieChart if you need them during migration.

Python SDK

All five chart types are available in the Python SDK:

from formepdf import BarChart, LineChart, PieChart, AreaChart, DotPlot

chart = BarChart(
    width=400,
    height=200,
    data=[
        {"label": "Q1", "value": 142000},
        {"label": "Q2", "value": 186000},
    ],
    color="#3b82f6",
    show_grid=True,
)

Try it

Update to 0.7.13:

npm install @formepdf/react@latest @formepdf/core@latest

Check out the templates/charts-showcase.tsx file in the repo for a two-page example using all five chart types together.