Charts in HTML to PDF: Chart.js, SVG and crisp output

Why charts come out blank, half-drawn or blurry in PDFs, and the settings that fix each problem.

Updated · 4 min read

Reports and dashboards almost always include charts, and charts are the elements most likely to come out wrong in a PDF: half-drawn, blank or fuzzy. The causes are predictable and easy to fix.

Problem 1: the chart is half-drawn or empty

Most chart libraries animate on first render. The converter captures the page once it has loaded, which can be part-way through that animation. Turn animation off for any chart going into a PDF.

Chart.js:

new Chart(ctx, {
  type: "bar",
  data,
  options: { animation: false, responsive: false },
});

Other libraries have equivalents, such as an animation or animationDuration: 0 option. Also make sure the chart’s data is in the page, not fetched later; see why a PDF is blank or missing content.

Problem 2: the chart is blurry

Canvas charts are images. A canvas sized for the screen gets scaled to fit the page and can look soft when zoomed or printed. Two fixes:

  • Draw at a higher pixel ratio. Chart.js accepts devicePixelRatio:
    options: { animation: false, responsive: false, devicePixelRatio: 3 }
  • Give the canvas a fixed size that fits the printable width (about 718 CSS pixels on A4 portrait with 10 mm margins). See page sizes in pixels.

Prefer SVG when you can

SVG charts are vectors: lines and text stay sharp at any zoom level, text remains selectable, and file sizes are usually smaller than high-resolution canvas images. Libraries that render SVG (for example D3, Recharts, Highcharts or Vega in SVG mode) are a good fit for PDFs. A pre-rendered SVG pasted directly into your HTML needs no JavaScript at all, which is the most reliable option:

<svg viewBox="0 0 400 160" width="100%" role="img" aria-label="Monthly sales: Jan 40, Feb 65, Mar 90">
  <rect x="20"  y="120" width="80" height="40"  fill="#163300"/>
  <rect x="160" y="95"  width="80" height="65"  fill="#163300"/>
  <rect x="300" y="70"  width="80" height="90"  fill="#163300"/>
</svg>

Keep charts on one page

.chart, figure { break-inside: avoid; }

Pair each chart with its title and caption inside a <figure> so they move to the next page together.

Load the library from a public URL

If your chart library comes from a CDN, the URL must be public and reachable. Loading Chart.js from jsDelivr worked in our test. If the script can’t load, the chart is never drawn, so check the preview. Inline scripts work too.

Colours

Chart fills are drawn, not CSS backgrounds, so they print regardless of the Print backgrounds setting. Background panels behind charts print too; the setting only removes a page background on html or body.