Chartist

Search

Find a guide, an API entry or an example.

Try

Security and CSP

Run Chartist on pages with a strict Content Security Policy or Trusted Types, and keep the data in your charts from injecting markup.

Charts often show what people typed: names, product titles, comments. Chartist keeps that text as text, and it runs on pages that lock down what scripts may do. This page covers what your policy needs to allow and what is up to you.

The policy Chartist needs

Nothing beyond your own origin. A policy like this one works:

<meta
  http-equiv="Content-Security-Policy"
  content="default-src 'self'; style-src 'self'"
/>

Chartist sets the few inline styles it needs (the chart’s size, the boxes of HTML labels, a donut’s width) through element.style, which a policy allows. It never sets a style attribute from a script, which style-src without 'unsafe-inline' blocks. It also evaluates no strings as code and adds no style sheets, so script-src needs no 'unsafe-eval' either.

Loading Chartist from a CDN? Add the CDN to script-src and style-src, for example https://cdn.jsdelivr.net.

The terminal package’s stylesheet brings its own font as a data: URL, so a page that shows text art also needs font-src data:. Without it, the browser falls back to the reader’s fonts, and the braille dots and grid lines may show gaps.

Server-rendered markup

The two server outputs differ here. The self-contained SVG image from renderToString() carries style attributes. In a page, a strict style policy blocks every one of them and reports it as a violation, and the chart loses what they set, such as a donut’s width. For a page with such a policy, render the chart with renderForHydration(). Its markup has no style attributes, looks the same with Chartist’s stylesheet, and once the chart takes it over, the chart sets its styles through element.style like every chart.

Your data stays data

Labels, series names, class names, meta and what your label functions return: Chartist writes all of it as text or as escaped attribute values, in the page, in renderToString() output and in the terminal’s text art. A label that contains markup shows its characters:

src/main.ts
import 'chartist/styles.css';
import { barChart } from 'chartist';

// Product names as people typed them into a form, markup and all.
const products = [
  'Tea & biscuits',
  '<b>Bold</b> coffee',
  '<img src=x onerror=alert(1)>'
];

// Chartist writes them as text: the labels show these characters, and
// nothing runs.
barChart('#chart', {
  labels: products,
  series: [[42, 31, 18]]
});
Live

Without innerHTML

Pages that require Trusted Types (require-trusted-types-for 'script') can’t assign strings to innerHTML. Chartist’s DOM renderer creates elements instead, so chart() and the presets need nothing. The same goes for liveDomRenderer() from chartist/live: it creates and changes elements the way the DOM renderer does, style through element.style included, and its update animations are SMIL elements, not style sheets.

Two outputs are strings on purpose. SVG markup from renderToString() is for servers and files (see Server rendering). In the browser, draw the same scene with domRenderer():

import { domRenderer, lineChartConfig, toScene } from 'chartist';

const scene = toScene(lineChartConfig({ series: [[1, 3, 2]] }), {
  width: 400,
  height: 200
});
const container = document.querySelector('#chart');
if (container) {
  domRenderer().render(scene, container);
}

And text art from the terminal package comes as an element with format: 'element':

import { lineChart } from '@chartist-js/terminal';

document
  .querySelector('#chart')
  ?.replaceChildren(lineChart({ series: [[1, 3, 2]] }, { format: 'element' }));

What’s up to you

  • 1.x Svg#foreignObject() takes a string as HTML, as it did in 1.x. Give it text you trust, or a DOM node (under Trusted Types, only a node works).
  • Plugins and listeners are your page’s code. What they add to a chart, such as an onclick attribute or a link, is theirs, and they follow your policy like any other script.
  • Strings you insert yourself: if you put renderToString() output into a page with innerHTML, it’s escaped, but Trusted Types still ask for a policy of your own.

Next: render charts on a server in Server rendering, or write plugins in Events and plugins.