chartist Documentation

TypeScript library by @chartist-js focused on charting-library, javascript, responsive-charts. Includes documentation and AI agent context with 13k stars.

13,422 stars TypeScript TypeScript 68 files · ~116,716 tokens #charting-library#chartist#javascript#responsive-charts#svg
RAW Doc

Technical Documentation: chartist-js/chartist

ℹ️ Provenance: Multi-Tier Ingestion · CodeWiki Reference

Overview (`README.md`)

Chartist

npm (next)
Downloads
Build status

Simple, responsive charts, drawn in SVG and styled with CSS. Tiny, typed, and happy without a build step.

chartist.dev · Getting started · API · Examples · Plugins · Changelog

Coming from Chartist 1? Your code keeps working. Coming from 1.x shows what's new, and the 1.x docs are at chartist.dev/v1/.

Install

sh
npm install chartist
ts
import { lineChart } from 'chartist';
import 'chartist/styles.css';

lineChart('#chart', {
  labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'],
  series: [
    [12, 9, 7, 8, 5],
    [2, 1, 3.5, 7, 3]
  ]
});
html
<div id="chart" class="ct-golden-section"></div>

No bundler? Chartist is a native ES module:

html
<link
  rel="stylesheet"
  href="https://cdn.jsdelivr.net/npm/chartist@2/dist/index.min.css"
/>
<div id="chart" class="ct-golden-section"></div>
<script type="module">
  import { lineChart } from 'https://cdn.jsdelivr.net/npm/chartist@2/dist/index.min.js';

  lineChart('#chart', { series: [[1, 3, 2, 5]] });
</script>

Why Chartist

  • Style it with CSS. Plain SVG with predictable classes and custom properties for colors, lines and labels. No theme engine.
  • Responsive, two ways. Options that change with media queries, or with the chart's own container.
  • Composed charts. Bars and lines in one chart, on as many axes as you need.
  • Renders anywhere SVG does. Render on a server, with real SVG text labels, for PDFs, email and images.
  • Extend everything. Every element passes through an open pipeline you can hook into, and the community's plugins keep working.
  • Tiny and typed. Written in TypeScript, no dependencies, and you ship only what you import.

Coming from 1.x

Your 1.x code keeps working: the chart classes draw what they drew before. 1.x events and plugins work with chartist/compat. The classes are deprecated, and 3.0 removes them from chartist. Coming from 1.x explains what changed and how to move to the functions.

Community wrappers

Chartist needs no wrapper: a chart is a container and a function call, and Charts in frameworks has recipes for React, Vue, Angular and Svelte, with server rendering. If you'd rather use a component, the community wraps Chartist for these stacks. Thank you to everyone who built them!

Stack Wrapper Built for
React react-chartist Chartist 1.x
Angular ng-chartist Chartist 1.x
Vue vue-chartist Chartist 0.x
Node.js node-chartist Chartist 0.x
Ember ember-cli-chartist Chartist 0.x
Java (JSF) ChartistJSF Chartist 0.x
Vue 2 v-chartist Chartist 0.x
R chartist (htmlwidget) Chartist 0.x
Meteor mfpierre:chartist-js Chartist 0.x
WordPress TablePress Extension: Chartist Chartist 0.x
Blazor UnlockedData.Chartist.Blazor Chartist 0.x
Angular ngx-chartist Chartist 0.x
Ruby on Rails chartist-rails Chartist 0.x

Wrappers built for 1.x run on v2: see Community wrappers for the npm overrides entry they need until they allow chartist@2. Maintain a wrapper that's missing here? Send a pull request.

Supported by

Cube sponsors Chartist's maintenance. Thank you!

Contributing

This repository holds the library (packages/chartist), its docs site at chartist.dev (apps/docs), the examples and the playground, in an Nx and pnpm monorepo. Clone it, run pnpm install, and run tasks through Nx, for example pnpm nx test chartist or pnpm nx dev docs. CONTRIBUTING.md has the setup, the tests and the submission guidelines.

License

Dual-licensed under MIT or WTFPL, at your choice.


Overview (`docs/visual-design/README.md`)

Visual design

Chartist's brand and the docs site's design were made in Claude Design. This folder is a snapshot of that canvas, kept as the design reference for the site.

  • Canvas: https://claude.ai/artifact/CFCX75HRhyT28hXYSNdgbU (snapshot of version 1791919724-153a)
  • Implemented in apps/docs: the tokens in src/styles/tokens.css, the mascot in src/components/Mascot.astro, the logomark in src/components/Logomark.astro. Styling rules: apps/docs/STYLING.md.

To change the design, change the site; the canvas is the reference for new pages and components, not a source the site is generated from. When the design itself changes in the canvas, download a new snapshot here and say what changed in the commit.

Contents

  • project/canvas.json: the canvas index (artboard titles, positions, grouping).
  • project/chartist.css: the design system. It holds the palette (--p-*), the semantic tokens for light (.cx) and dark (.cx.dark), the mascot colors (--m-*), the chart series palette (--ct-series-*, including the accessible theme), and component styles.
  • project/*.dc.html: one file per artboard.
  • project/paper.png, project/paper-dark.png: the design's paper texture, "Cream Paper" from Subtle Patterns (CC BY-SA 3.0). The site uses it as the page ground texture (apps/docs/src/assets/).
  • assets/reference-*-0x.svg: the original 2014 mascot and icon, uploaded as a reference for the redesign.

The .dc.html files are Claude Design component pages. They need the Design runtime (support.js, not included) to render, so read them as source (markup, tokens, copy, data), and open the canvas link to see them rendered.

Group Artboards
Brand Main (overview and rationale), MascotPoses, Logo
Brand system Color, Typography, VoiceMotion, Tokens (tokens → chart theme), OgCard
Components (Astro islands) Mascot, Logomark, Chart, LiveExample, SiteHeader, SiteFooter, ComparisonTable, ScrollStage
Docs pages (desktop) Landing (scroll story), LandingStory (storyboard), GettingStarted, Examples, Playground, Api, Plugins, NotFound
Dark mode and mobile LandingDark, MobileLanding, MobileDocs, MobilePlayground, MobileNotFound

The design's key choices

  • Mascot: the 0.x gentleman (top hat, moustache, red waistcoat, easel, hay fork), redrawn. All his colors are custom properties.
  • Palette: cream became Paper, red became Waistcoat (#C8102E), yellow became Mustard (logo tile), warm gray became Ink.
  • Chart series colors: unchanged from 1.5 (--ct-series-a … -o), plus an opt-in color-blind-safe theme.
  • Typography: Zilla Slab (display) and Atkinson Hyperlegible Next (body).

Where the site differs from the snapshot

  • Code font: JetBrains Mono instead of Atkinson Hyperlegible Mono. All fonts are self-hosted.
  • Code samples use the functional API and the real export paths; the design's samples use the 1.x classes and old paths.
  • Charts are drawn by Chartist. The design's Chart component draws them with its own simplified math, as a mockup.
  • Numbers and comparisons on the landing page come from a dated facts snapshot (pnpm nx run docs:facts) and measurements, where the design has placeholders. The design's "Trusted by" logo row became a curated "Used by" list that links to the evidence.

Overview (`packages/chartist/README.md`)

Chartist

npm (next)
Downloads
Build status

Simple, responsive charts, drawn in SVG and styled with CSS. Tiny, typed, and happy without a build step.

chartist.dev · Getting started · API · Examples · Plugins · Changelog

Coming from Chartist 1? Your code keeps working. Coming from 1.x shows what's new, and the 1.x docs are at chartist.dev/v1/.

Install

sh
npm install chartist
ts
import { lineChart } from 'chartist';
import 'chartist/styles.css';

lineChart('#chart', {
  labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'],
  series: [
    [12, 9, 7, 8, 5],
    [2, 1, 3.5, 7, 3]
  ]
});
html
<div id="chart" class="ct-golden-section"></div>

No bundler? Chartist is a native ES module:

html
<link
  rel="stylesheet"
  href="https://cdn.jsdelivr.net/npm/chartist@2/dist/index.min.css"
/>
<div id="chart" class="ct-golden-section"></div>
<script type="module">
  import { lineChart } from 'https://cdn.jsdelivr.net/npm/chartist@2/dist/index.min.js';

  lineChart('#chart', { series: [[1, 3, 2, 5]] });
</script>

Why Chartist

  • Style it with CSS. Plain SVG with predictable classes and custom properties for colors, lines and labels. No theme engine.
  • Responsive, two ways. Options that change with media queries, or with the chart's own container.
  • Composed charts. Bars and lines in one chart, on as many axes as you need.
  • Renders anywhere SVG does. Render on a server, with real SVG text labels, for PDFs, email and images.
  • Extend everything. Every element passes through an open pipeline you can hook into, and the community's plugins keep working.
  • Tiny and typed. Written in TypeScript, no dependencies, and you ship only what you import.

Coming from 1.x

Your 1.x code keeps working: the chart classes draw what they drew before. 1.x events and plugins work with chartist/compat. The classes are deprecated, and 3.0 removes them from chartist. Coming from 1.x explains what changed and how to move to the functions.

Community wrappers

Chartist needs no wrapper: a chart is a container and a function call, and Charts in frameworks has recipes for React, Vue, Angular and Svelte, with server rendering. If you'd rather use a component, the community wraps Chartist for these stacks. Thank you to everyone who built them!

Stack Wrapper Built for
React react-chartist Chartist 1.x
Angular ng-chartist Chartist 1.x
Vue vue-chartist Chartist 0.x
Node.js node-chartist Chartist 0.x
Ember ember-cli-chartist Chartist 0.x
Java (JSF) ChartistJSF Chartist 0.x
Vue 2 v-chartist Chartist 0.x
R chartist (htmlwidget) Chartist 0.x
Meteor mfpierre:chartist-js Chartist 0.x
WordPress TablePress Extension: Chartist Chartist 0.x
Blazor UnlockedData.Chartist.Blazor Chartist 0.x
Angular ngx-chartist Chartist 0.x
Ruby on Rails chartist-rails Chartist 0.x

Wrappers built for 1.x run on v2: see Community wrappers for the npm overrides entry they need until they allow chartist@2. Maintain a wrapper that's missing here? Send a pull request.

Supported by

Cube sponsors Chartist's maintenance. Thank you!

License

Dual-licensed under MIT or WTFPL, at your choice.


Overview (`packages/essentials/README.md`)

@chartist-js/essentials

The Chartist additions people ask for most, as layers you add to a chart. They're kept out of the core, so charts that don't use them stay small, and they're made and released together with Chartist.

It holds axisTitle(), targetLine(), trendLine(), valueLabels() and logAxis() today. More layers and axes follow.

Install

sh
npm install @chartist-js/essentials

It depends on chartist, which npm installs with it. Load its stylesheet after Chartist's:

ts
import 'chartist/styles.css';
import '@chartist-js/essentials/styles.css';

Without a bundler

Map both packages in an import map, so the package and your page share one copy of Chartist:

html
<link
  rel="stylesheet"
  href="https://cdn.jsdelivr.net/npm/chartist@2/dist/index.css"
/>
<link
  rel="stylesheet"
  href="https://cdn.jsdelivr.net/npm/@chartist-js/essentials@2/dist/styles.css"
/>
<script type="importmap">
  {
    "imports": {
      "chartist": "https://cdn.jsdelivr.net/npm/chartist@2/dist/index.min.js",
      "@chartist-js/essentials": "https://cdn.jsdelivr.net/npm/@chartist-js/essentials@2/dist/index.js"
    }
  }
</script>
<script type="module">
  import { lineChart } from 'chartist';
  import { axisTitle } from '@chartist-js/essentials';
</script>

Axis titles

axisTitle() names an axis. It reserves the room the title needs next to the axis labels, so you don't have to guess a padding, and the title never overlaps the labels:

ts
import { lineChart } from 'chartist';
import { axisTitle } from '@chartist-js/essentials';

lineChart(
  '#chart',
  { labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'], series: [[12, 9, 7, 8, 5]] },
  {
    layers: {
      above: [
        axisTitle({ axis: 'x', text: 'Day' }),
        axisTitle({ axis: 'y', text: 'Visits' })
      ]
    }
  }
);

One layer draws one title. On the presets the axes are x and y; in a composed chart, use the ids you gave the axes:

ts
import {
  autoScaleAxis,
  axisGrid,
  axisLabels,
  cartesianAxes,
  chart,
  line,
  stepAxis
} from 'chartist';
import { axisTitle } from '@chartist-js/essentials';

chart('#chart', {
  data: {
    labels: ['Jan', 'Feb', 'Mar', 'Apr'],
    series: [
      [120, 150, 170, 210],
      [135, 160, 190, 230]
    ]
  },
  axes: cartesianAxes([
    { id: 'month', side: 'bottom', type: stepAxis() },
    { id: 'eur', side: 'left', type: autoScaleAxis() },
    { id: 'usd', side: 'right', type: autoScaleAxis() }
  ]),
  layers: [
    axisGrid({ axes: ['month', 'eur'] }),
    line({ series: [0], x: 'month', y: 'eur' }),
    line({ series: [1], x: 'month', y: 'usd' }),
    axisLabels(),
    axisTitle({ axis: 'month', text: 'Month', align: 'end' }),
    axisTitle({ axis: 'eur', text: 'EUR' }),
    axisTitle({ axis: 'usd', text: 'USD', flip: true })
  ]
});
Option What it does
axis The id of the axis to name
text The title; an empty text draws nothing
align start, middle (default) or end along the axis; the start of a Y axis is its bottom
flip Left and right titles read from top to bottom instead of from bottom to top
gap Space between the title and the axis labels, in px (default 4)
className Extra classes for the title
classNames { title } replaces the class ct-axis-title

Titles on the same side stack outward in the order of layers.

Styling

The title is an SVG text with the classes ct-axis-title, ct-horizontal or ct-vertical, and ct-start or ct-end. It looks like the axis labels until you say otherwise:

css
.ct-axis-title {
  --ct-axis-title-color: #555;
  --ct-axis-title-size: 0.875rem;
  font-weight: 600;
}

Target and trend lines

targetLine() draws a line across the chart at a value, such as a goal or a limit, with an optional label. trendLine() fits a straight line through each series' values (least squares) and draws it in the series' color:

ts
import { lineChart } from 'chartist';
import { targetLine, trendLine } from '@chartist-js/essentials';

lineChart(
  '#chart',
  {
    labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'],
    series: [[620, 810, 740, 930, 880, 1020]]
  },
  {
    low: 0,
    layers: {
      above: [targetLine({ value: 1000, label: 'Goal' }), trendLine()]
    }
  }
);

A target line takes value, label, className, the axis it's on (a Y axis draws it across, an X axis up and down) and where its label sits. A trend line's node knows its slope, intercept and correlation. On a log axis it's fitted to the logarithms, so it's straight there. Style them with --ct-target-line-color, --ct-target-line-width, --ct-target-line-dasharray, --ct-trend-line-width and --ct-trend-line-dasharray.

Value labels

valueLabels() writes each value next to its point or bar: above points, past the ends of bars, and in the middle of stacked segments. Labels that don't fit their bar or would leave the chart move to where they fit:

ts
import { barChart } from 'chartist';
import { valueLabels } from '@chartist-js/essentials';

barChart(
  '#chart',
  { labels: ['Q1', 'Q2', 'Q3'], series: [[1250, 1830, 1470]] },
  {
    layers: {
      above: [
        valueLabels({
          locale: 'en-US',
          numberFormat: { style: 'currency', currency: 'USD' }
        })
      ]
    }
  }
);

format(item) gets the same item as the format of @chartist-js/tooltips: undefined keeps the default text, null draws no label, and \n starts a new line. pointPosition, barPosition and offset place the labels, roles and series pick what gets one. Style them with --ct-value-label-color, --ct-value-label-inside-color and --ct-value-label-size.

Log axis

logAxis() is an axis type for values that span several orders of magnitude. Each power of the base is the same distance from the next, so 100, 1,000 and 10,000 are evenly spaced:

ts
import { lineChart } from 'chartist';
import { logAxis } from '@chartist-js/essentials';

lineChart(
  '#chart',
  {
    labels: ['2019', '2020', '2021', '2022', '2023', '2024'],
    series: [[120, 980, 4100, 36000, 210000, 850000]]
  },
  {
    axisY: {
      type: logAxis({ minorTicks: true }),
      labelTransform: value => value.toLocaleString('en-US')
    }
  }
);
Option What it does
base The base of the logarithm, any number above 1 (default 10)
minorTicks Grid lines without labels between the ticks, styled with --ct-grid-minor-* (default off)

The axis's own options work as on the core's axes: low and high set the range exactly, ticks sets the ticks by hand, and labelTransform formats the labels. Zero and negative values have no place on a log scale: they're drawn at the start of the axis. Use null for a gap. A trendLine() on a log axis is fitted to the logarithms, so it's straight on the chart.

On the server

The layers and the log axis are part of the scene, so they render with chartist/server and hydrate like the rest of the chart:

ts
import { lineChartConfig } from 'chartist';
import { renderToString, toScene } from 'chartist/server';
import { axisTitle } from '@chartist-js/essentials';

const config = lineChartConfig(
  { labels: ['Mon', 'Tue', 'Wed'], series: [[12, 9, 7]] },
  { layers: { above: [axisTitle({ axis: 'y', text: 'Visits' })] } }
);
console.log(renderToString(toScene(config, { width: 600, height: 300 })));

@chartist-js/terminal draws them too, vertical titles in a column.

License

MIT or WTFPL, like Chartist. See chartist.dev for the guides.


Overview (`packages/examples/README.md`)

@chartist/examples

The Chartist examples, shared by the docs site, the live playground and the visual regression tests (packages/visual). Private, never published.

Example format

Each example is a folder laid out like an npm create vite vanilla TypeScript starter (minus package.json):

text
<type>/<name>/
  index.html     the chart container and <script type="module" src="/src/main.ts">
  src/main.ts    imports 'chartist/styles.css' and the chart from 'chartist'
  src/style.css  optional, imported from src/main.ts

Copy a folder into a Vite app that has chartist installed and it runs unchanged. Examples contain only code a user would write for that chart:

  • no harness, test or docs code;
  • only erasable TypeScript syntax (no enums, namespaces, parameter properties or decorators), with type-only imports marked type;
  • CSS imported from TypeScript (chartist/styles.css, relative ./style.css), and no Vite-specific features (import.meta.glob, ?raw, path aliases);
  • seeded randomness (an inlined mulberry32) instead of Math.random(), so every render is identical.

src/main.ts uses the functional API (lineChart(), chart(), v2 plugins) and teaches v2: when JavaScript would only style an element, it uses the custom properties (--ct-bar-width, --ct-color, …) or a class and a rule in src/style.css.

Each example has an entry in the manifest, index.ts (title, a one-sentence description for the gallery card and the example's page, viewports, sizing, settle time). pnpm nx check examples keeps the manifest and the folders in sync.

Classic entries

Every example that came from 1.x also has src/main.classic.ts, its original 1.x code (classic: true in the manifest; compat: true when that code needs the compat plugin). Never edit a classic file, comments included: it's the 1.x original. The docs show it behind the example's v2 / 1.x switch.

The visual tests screenshot both entries against one baseline image, recorded from Chartist 1.5.0 with the classic code, which proves that the functions draw what the classes drew. When the two differ:

  1. Suspect the functional code first: an option in the wrong place, a different default, a node replaced at a different position, attributes in a different order.
  2. If v2 draws it differently on purpose, give the entry a reason in the manifest and a baseline from the local build: ownBaseline when only the functional entry differs, localBaseline when v2 changes the chart for both APIs (the 1.5.0 run then skips it).
  3. If it's a library bug, fix the library (with a GitHub issue labeled v2), not the example.

New examples have no 1.x code (v2: true); their baselines come from the local build, and the 1.5.0 run skips them. Baselines are recorded only on the reference platform (see "Visual regression" in docs/decisions.md).

Commands

  • pnpm nx typecheck examples: type-checks every example in strict mode against the built chartist declarations (builds chartist first).
  • pnpm nx check examples: validates the manifest against the folders.
  • pnpm nx run visual:test:visual: screenshots every example (see packages/visual).

Coverage of the 1.x examples

The 32 1.x CodeSandbox examples (sandboxes/ at the v1.5.0 tag) moved here in the Vite format. Their history follows the files: git log --follow <type>/<name>/src/main.ts for the functional code, which was rewritten in place, and git log --follow -C on src/main.classic.ts, a copy of the 1.x code.

Every 1.x Storybook story (src/charts/*/*.stories.ts) maps to an example. A story was merged into a sandbox example only if its data, options and event handlers are identical (same values and same behavior). All other stories became test-only examples (docs: false), with these changes:

  • the detached root element became the #chart container;
  • faker (story LineChart/Scatter) became an inlined seeded mulberry32, still drawing whole numbers from 0 to 100;
  • new Date() (story PieChart/OverlappingLabels) became a fixed date;
  • PieChart/GaugeDonut and PieChart/RelativeDonutWidth draw a fixed 500×500 chart, so their container has no fixed height and the tests keep its size (size: 'viewport').

LineChart/PathAnimation skipped its animation in storyshots; line/path-animation animates and the tests screenshot its end state. The viewports column lists the story's storyshots viewports (iPad → tablet, iPhone X → mobile, iPhone X landscape → mobile-landscape); pnpm nx check examples asserts that this table matches the manifest.

Story Example Viewports Mapping
LineChart/Default line/simple default merged
LineChart/AutoScale line/auto-scale default test-only
LineChart/Labels line/labels default test-only
LineChart/MultiSeries line/multi-series default test-only
LineChart/Holes line/data-holes default merged
LineChart/FilledHoles line/data-fill-holes default merged
LineChart/OnlyWholeNumbers line/only-integer default merged
LineChart/NoInterpolationWithHoles line/no-interpolation-with-holes default test-only
LineChart/CardinalInterpolationWithHoles line/cardinal-interpolation-with-holes default test-only
LineChart/MonotoneCubicInterpolationWithHoles line/monotone-cubic-interpolation-with-holes default test-only
LineChart/SimpleInterpolationWithHoles line/simple-interpolation-with-holes default test-only
LineChart/StepInterpolationWithHoles line/step-interpolation-with-holes default test-only
LineChart/StepNoPostponeInterpolationWithHoles line/step-no-postpone-interpolation-with-holes default test-only
LineChart/SeriesOverrides line/series-override default merged
LineChart/ReverseData line/reverse-data default test-only
LineChart/FullWidth line/full-width default test-only
LineChart/Scatter line/scatter default test-only (integer data, unlike line/scatter-random)
LineChart/Area line/area default merged
LineChart/BiPolarArea line/bipolar-area default merged
LineChart/CustomPoints line/modify-drawing default merged
LineChart/PathAnimation line/path-animation default merged
LineChart/ViewBox line/view-box default test-only
BarChart/Default bar/auto-scale default test-only
BarChart/BiPolar bar/bi-polar-interpolated default merged
BarChart/Labels bar/labels default test-only
BarChart/MultilineLabels bar/multiline default merged
BarChart/LabelsPlacement bar/label-position default merged
BarChart/MultiSeries bar/multi-series default test-only
BarChart/DistributedSeries bar/distributed-series default merged
BarChart/ReverseData bar/reverse-data default test-only
BarChart/Stack bar/stacked default merged
BarChart/Horizontal bar/horizontal default merged
BarChart/Adaptive bar/adaptive default, tablet, mobile-landscape, mobile test-only (hides labels, unlike bar/extreme-responsive's noop)
BarChart/OverlappingBarsOnMobile bar/overlapping-bars-on-mobile default, mobile test-only (other data and breakpoints than bar/overlapping-bars)
BarChart/PeakCircles bar/with-circle-modify-drawing default merged
BarChart/AccumulateRelativeStack bar/stacked-accumulate-relative default merged
BarChart/ViewBox bar/view-box default test-only
PieChart/Default pie/fixed-size default test-only
PieChart/Labels pie/labels default test-only
PieChart/OverlappingLabels pie/overlapping-labels default test-only
PieChart/LabelInterpolation pie/label-interpolation default test-only (fixed size, unlike pie/simple)
PieChart/StartAngle pie/start-angle default test-only
PieChart/SmallSlices pie/small-slices default test-only
PieChart/IgnoreEmptyValues pie/ignore-empty-values default test-only
PieChart/Donut pie/donut default test-only
PieChart/GaugeDonut pie/gauge-donut default test-only (fixed size and padding, unlike pie/simple-gauge)
PieChart/RelativeDonutWidth pie/relative-donut-width default test-only
PieChart/Solid pie/donut-chart default merged
PieChart/ViewBox pie/view-box default test-only

Overview (`packages/playground/README.md`)

@chartist/playground

In-browser playground for Chartist example projects: an editor with file tabs and a live preview of a Vite-style example (index.html, src/main.ts, src/style.css), without a server. Private, not published. Spec: openspec/specs/example-playground/spec.md.

How it works:

  1. Strip TypeScript in the browser (sucrase by default, ts-blank-space optional).
  2. Turn CSS imports from TypeScript into <link>/<style> tags.
  3. Resolve relative imports to data-URL modules through an import map, which also maps chartist to a configurable URL.
  4. Render the result into an `` via srcdoc. Errors and console output come back through postMessage.
ts
import { createPlayground } from '@chartist/playground';

await createPlayground(document.querySelector('#playground')!, {
  files: { 'index.html': '…', 'src/main.ts': '…' },
  chartistUrl: '/lib/chartist/index.js', // must send Access-Control-Allow-Origin
  stylesUrl: '/lib/chartist/index.css',
  types: { url: '/lib/chartist/' }, // index.d.ts and compat.d.ts, optional
  chartistVersion: '^1.5.0' // for "Open in StackBlitz"
});

compile(files, options) is the DOM-free core, usable on its own.

With types, TypeScript files get type errors (underlined; Ctrl/Cmd+Shift+M lists them), completions (on ., while typing, Ctrl+Space) and the type and doc comment of a name on hover. The TypeScript language service runs in a worker (src/types/), one per page, which loads when a TypeScript editor first gets focus: about 1.3 MB compressed with the lib declarations, from the page's own origin. Type errors never stop the preview. The playground element gets data-types="ready" once types answer. CSS files complete the stylesheet's --ct-* properties.

Tasks

Command What it does
pnpm nx dev playground Demo with the example fixtures in demo/examples (Vite dev server)
pnpm nx build playground Static demo in dist/, base path /chartist/
pnpm nx preview playground Serves dist/ at http://localhost:4321/chartist/ (see below)
pnpm nx test playground Unit tests of the compile pipeline (Vitest)
pnpm nx run playground:test:e2e Playwright, Chromium + Firefox + WebKit, against the built demo
pnpm nx run playground:measure Bundle sizes and transformer timings

The preview uses the docs dev server's port; while that runs, serve the demo on another one with node test/e2e/serve.mjs (from packages/playground). The e2e tests use port 4331.

Browsers for the e2e test: pnpm --filter @chartist/playground exec playwright install chromium firefox webkit.

The demo URL takes ?example=&transformer=sucrase|ts-blank-space, and &types=off for plain editing.

"Open in StackBlitz" can only be checked by hand: it opens stackblitz.com in a new tab.


Overview (`packages/terminal/README.md`)

@chartist-js/terminal

Chartist charts in the terminal. Line, bar and pie charts with Chartist's own layout, labels and series colors, drawn in braille dots and block characters:

It renders the scene Chartist builds for any chart (toScene()), the same one the SVG renderers get. So a terminal chart takes the options you know from lineChart(), barChart() and pieChart(), and the same chart can also come out as text-art HTML.

There are two ways to use it: the ct-cli command, and an API for your own CLI tools.

Install

sh
npm install @chartist-js/terminal

It depends on chartist, which npm installs with it. The command needs Node.js 22 or later; the API runs in any JavaScript runtime, browsers included.

The command

sh
npx @chartist-js/terminal demo

Installed globally (npm install @chartist-js/terminal), the command is ct-cli. Give it a chart type and the series, each a comma-separated list of numbers:

sh
ct-cli line 12,9,7,8,5 2,1,3.5,7,3 --labels Mon,Tue,Wed,Thu,Fri --names Visitors,Sign-ups --smooth --area
ct-cli bar 5,4,3,7 3,2,9,5 --labels Q1,Q2,Q3,Q4 --stack
ct-cli bar 5,3,8 --labels Bananas,Apples,Kiwis --horizontal
ct-cli pie 20,10,30 --labels Bananas,Apples,Kiwis --donut

An empty value is a hole: 1,,3.

Data from files and pipes

Without series arguments, the data comes from --data <file> or from stdin. JSON works as { "labels": [...], "series": [...] } or as a plain array:

sh
echo '{"labels":["Bananas","Apples","Kiwis"],"series":[20,10,30]}' | ct-cli pie --donut

Anything else is read as rows of values, one series per row, separated by commas, semicolons, tabs or spaces. A first row that isn't numbers is the labels, and a first column that isn't numbers is the series names:

sh
printf ',Mon,Tue,Wed\nVisitors,3,5,4\nSign-ups,1,2,3\n' | ct-cli bar --stack

Options

Option What it does
-d, --data <file> Reads the data from a file
-l, --labels <a,b,c> Labels of the values, or of the slices
-n, --names <a,b> Series names, shown in a legend
-w, --width <columns> Width in columns; your terminal's width by default
-h, --height <rows> Height in rows; 20 by default
--low, --high <n> The value axis range
--smooth Line: smooths the lines
--area Line: fills the area below the lines
--no-points Line: hides the points
--stack Bar: stacks the series
--horizontal Bar: draws horizontal bars
--donut Pie: draws a donut
--no-labels Pie: hides the slice labels
--palette <#hex,…> Series colors, first series first
--no-legend Leaves out the legend
--color <mode> auto, truecolor, 256, 16 or none; auto by default
--html Prints HTML instead of text
--standalone With --html: a complete page, styles included
--help, --version What you'd expect

-h is the height. Help is --help.

Colors follow your terminal: 24-bit when COLORTERM says so, 256 colors otherwise, none when the output goes to a file or a pipe, when NO_COLOR is set or TERM is dumb. FORCE_COLOR (0 to 3) overrides that, and --color overrides everything.

In your CLI tool

lineChart(), barChart() and pieChart() take the data and options of Chartist's presets, plus a size in columns and rows, and return the chart as a string:

ts
import { detectColorMode, legend, lineChart } from '@chartist-js/terminal';

const data = {
  labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'],
  series: [
    { name: 'Visitors', data: [12, 9, 7, 8, 5] },
    { name: 'Sign-ups', data: [2, 1, 3.5, 7, 3] }
  ]
};
const color = detectColorMode(process.stdout, process.env);

console.log(
  lineChart(data, {
    columns: 60,
    rows: 14,
    showArea: true,
    lineSmooth: true,
    color
  })
);
console.log(legend(data, { columns: 60, color }));

The Chartist options work as they do in the browser: stackBars, horizontalBars, low and high, axisY.labelTransform, donut and the others. The terminal options are:

  • columns and rows: the size in cells, 80 × 20 by default;
  • color: truecolor (default), 256, 16 or none for plain text;
  • palette: series colors as hex, first series first, Chartist's colors by default;
  • format: text (default), html for a string of HTML, or element for the same markup as a pre element.

detectColorMode(stream, env) picks the color mode the way the command does; pass it process.stdout and process.env.

Any chart, any scene

The chart functions are shortcuts. For a composed chart, or a scene a plugin changed, lay it out with terminalSize() and render it yourself:

ts
import { barChartConfig, toScene } from 'chartist';
import { renderToTerminal, terminalSize } from '@chartist-js/terminal';

const scene = toScene(
  barChartConfig({ labels: ['Q1', 'Q2', 'Q3'], series: [[5, 4, 3]] }),
  terminalSize(40, 10)
);
console.log(renderToTerminal(scene, { color: 'none' }));

A cell stands for 8 × 16 px, so a braille dot is 4 × 4 px and circles stay round; terminalSize() measures text one cell per character, so labels land on the character grid. Nodes a plugin adds are drawn by their element: line and path as lines, circle as a filled disc of its radius (a point when it's tiny), text as a label.

HTML output

renderToHtml(scene), or format: 'html', gives the same chart as HTML: a pre element with classes instead of colors, ct-series-a, ct-grid, ct-label and so on. In a browser, renderToElement(scene), or format: 'element', builds that pre element with DOM methods, so the page needs no innerHTML, also where a Content Security Policy requires Trusted Types. Load the stylesheet to color it:

ts
import '@chartist-js/terminal/styles.css';
import { lineChart } from '@chartist-js/terminal';

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

Every character sits in a cell 0.6 × 1 em, and the stylesheet brings a small font of its own (embedded, under 5 kB) for the braille dots, the grid and the bar blocks, drawn to fill a cell edge to edge. Fonts on the reader's system rarely have all of those, so the text art looks the same in every browser. Letters and digits use a monospace font: JetBrains Mono when the page loads it, else the system's. The stylesheet reads Chartist's custom properties (--ct-series-a to --ct-series-o, --ct-grid-color, --ct-label-color), so your Chartist theme colors the text art too. ct-cli --html --standalone writes a complete page.

Fonts

In a terminal, braille and box-drawing characters need a font that has them. Most terminal fonts do; on Windows, Cascadia Mono works. If the dots look scattered or the grid has gaps, your font is missing them. HTML output brings its own font for them, so it doesn't depend on the reader's fonts. The stylesheet embeds it as a data: URL, so a page with a Content Security Policy needs font-src data:; without it, the browser falls back to the reader's fonts.

Limits

  • Line, bar and pie charts, and the nodes listed above. Other layers draw what their nodes are made of, or nothing.
  • Each character of a label is one cell, so wide characters (CJK, emoji) shift the columns after them.
  • No animation, no interaction: it prints a chart and is done.

License

MIT or WTFPL, like Chartist. See chartist.dev for the guide.


Overview (`packages/tooltips/README.md`)

@chartist-js/tooltips

Tooltips for Chartist charts: hover a point, tap a bar or tab to a slice, and a tooltip shows its label, series and value. It works with the mouse, touch and the keyboard, stays on its value while the chart updates, and takes its looks from CSS.

Install

sh
npm install @chartist-js/tooltips

It brings chartist along. Load its stylesheet after Chartist's, and add the plugin to a chart:

ts
import 'chartist/styles.css';
import '@chartist-js/tooltips/styles.css';
import { lineChart } from 'chartist';
import { tooltips } from '@chartist-js/tooltips';

lineChart(
  '#chart',
  {
    labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'],
    series: [{ name: 'Visitors', data: [1200, 1500, 1350, 1600, 1100] }]
  },
  { plugins: [tooltips()] }
);

Without a bundler

The browser build imports nothing, so it works next to any copy of Chartist 2:

html
<link
  rel="stylesheet"
  href="https://cdn.jsdelivr.net/npm/chartist@2/dist/index.css"
/>
<link
  rel="stylesheet"
  href="https://cdn.jsdelivr.net/npm/@chartist-js/tooltips@2/dist/styles.css"
/>
<div id="chart"></div>
<script type="module">
  import { lineChart } from 'https://cdn.jsdelivr.net/npm/chartist@2/dist/index.min.js';
  import { tooltips } from 'https://cdn.jsdelivr.net/npm/@chartist-js/tooltips@2/dist/index.min.js';

  lineChart('#chart', { series: [[5, 9, 7, 8, 5]] }, { plugins: [tooltips()] });
</script>

Your own text

numberFormat sets how the default text writes values, as Intl.NumberFormat options, and format replaces the text. Return null for no tooltip:

ts
import { barChart } from 'chartist';
import { tooltips } from '@chartist-js/tooltips';

barChart(
  '#chart',
  { labels: ['Q1', 'Q2', 'Q3'], series: [[1250, 1830, 1470]] },
  {
    plugins: [
      tooltips({ numberFormat: { style: 'currency', currency: 'CHF' } })
    ]
  }
);

barChart(
  '#other',
  { labels: ['Q1', 'Q2', 'Q3'], series: [[12, 18, 0]] },
  {
    plugins: [
      tooltips({
        format: item =>
          item.value === 0
            ? null
            : `${item.label}\n${String(item.value)} orders`
      })
    ]
  }
);

Content is text, never HTML, so data can't put markup into the page. For markup or a framework's template, render fills the tooltip yourself:

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

lineChart(
  '#chart',
  { series: [[5, 9, 7]] },
  {
    plugins: [
      tooltips({
        render(content, item) {
          const value = document.createElement('strong');
          value.textContent = String(item.valueIndex);
          content.append('Value ', value);
          // Return a function to undo it, e.g. to unmount a component.
        }
      })
    ]
  }
);

Options

Option What it does
roles The roles that get tooltips: point, bar and slice by default; any role works
format The text of a tooltip; null for none
render Fills the tooltip with your own content; may return a cleanup
numberFormat Intl.NumberFormat options for the values
position element (default) at the value, or pointer to follow the mouse
keyboard One tab stop per chart and arrow keys between values; false to turn it off
className Extra classes for the tooltip

Styling

The tooltip is .ct-tooltip, with .ct-tooltip-title, .ct-tooltip-series and .ct-tooltip-value. Change its look with custom properties, on the page or a chart's container:

css
.my-chart {
  --ct-tooltip-background: navy;
  --ct-tooltip-color: white;
  --ct-tooltip-hide-delay: 500ms;
}

It shows in the top layer, so overflow: hidden and z-index don't cut it off, and it's placed with the CSSOM, so it works under a strict Content Security Policy.

License

MIT or WTFPL, like Chartist. See chartist.dev for the guides.


Overview (`apps/docs/public/v0/README.md`)

The 0.x docs

These files are the Chartist 0.11 documentation, formerly at
https://gionkunz.github.io/chartist-js/. Astro copies them to /v0/ of the
site as they are. The old URLs redirect to chartist.dev: pages without a
#hash to their v2 counterpart, sections without one to the same place
here.

They are not edited by hand beyond the changes listed below. The 0.x
toolchain (Grunt, Assemble, Bower) isn't kept.

Where they come from

The gh-pages branch of gionkunz/chartist-js at c1e49e1 (August 2022),
the last build of the 0.x site. Copied: the six pages (index.html,
getting-started.html, examples.html, api-documentation.html,
plugins.html, apidoc/index.html) and the files they load
(scripts/all.js, styles/, images/, favicon.ico, apidoc/scripts/,
apidoc/styles/).

Not copied, because no page loads them: bower_components/ (most of the
build's 19 MB), test-chart.html, doc-clean-pull.sh, 404.html and
robots.txt.

What changed

  • Removed the "Get awesome Dashboard Templates by Creative Tim" section
    of the home page, its .affiliate-project* CSS and its three images on
    S3; the Google Analytics snippet on every page; the version notice pop-up
    added in 2022 (its markup, CSS and script); and the html5shiv script for
    IE 8 in apidoc/index.html, whose host is gone.
  • Fonts are served from fonts/ instead of Google Fonts and cdnjs: the
    WebFont loader snippet on each page is replaced by a link to
    fonts/fonts.css, which loads Oxygen 300/400/700 and Source Code Pro
    400/700 (SIL OFL 1.1, latin subset from fontsource) and Font Awesome
    4.1.0. Their licenses are next to them. With this, no page makes a request
    to another host.
  • Added a note at the top of each page: "This is the archived
    documentation of Chartist 0.11. The current docs are at chartist.dev." Its
    <style> sits next to it.
  • apidoc/index.html shows images/chartist-icon.svg instead of a
    Chartist Guy GIF on raw.github.com that no longer exists.

Overview (`apps/docs/public/v1/README.md`)

The 1.x docs

These files are the Chartist 1.5.x documentation (formerly at
https://chartist.dev/), the static output of its Docusaurus website. Astro
copies them to /v1/ of the site as they are.

They are not edited by hand. The 1.x docs won't be updated again, so the
Docusaurus stack isn't kept; if they ever need to change, rebuild them as
below and replace this folder.

How they were built

Built once on 2026-10-14, from the v1.5.0 sources (website/ of
chartist-js/chartist at the v1.5.0 tag, plus the commit after it that
removed the analytics):

  1. Copy the 1.x repository to a scratch folder outside this repository.
  2. In website/docusaurus.config.js: baseUrl: '/v1/', noIndex: false, and
    no editUrl (there is nothing to edit any more). url stays
    https://chartist.dev; trailingSlash stays false, because the
    generated API pages link each other relatively (../#series).
  3. pnpm@7 install --frozen-lockfile --ignore-scripts (the 1.x lockfile is
    pnpm 7's), then BRANCH=v1.5.0 docusaurus build in website/ with Node 22.
    BRANCH sets the tree of the CodeSandbox example embeds, so they show the
    1.5.0 sandboxes.
  4. Copy website/build/ here (there are no source maps).

Pages are .html files linked without the extension (/v1/api/basics), as
Docusaurus writes them with trailingSlash: false; the host serves
page.html for /page, as GitHub Pages does.


Overview (`apps/docs/src/assets/README.md`)

Assets

  • paper.png, paper-dark.png: the page ground texture, from the design (docs/visual-design/project/). Based on "Cream Paper" from Subtle Patterns (Toptal), licensed under CC BY-SA 3.0, recolored as an overlay for the Chartist v2 design. These two files stay under CC BY-SA 3.0 and need visible attribution on the site.
  • sponsors/cube-logo-light.svg, sponsors/cube-logo-dark.svg: Cube's logo for light and dark grounds, unchanged from Cube's brand kit (https://cube.dev/brand, downloaded 2026-10-14). Its rules: use the files as provided (no recoloring or effects), the matching file for each ground instead of inverting, clear space of at least the cube mark's width around the logo, and no implied partnership beyond the real one (Cube sponsors Chartist).

Apps Docs Src Content Docs Getting Started (`apps/docs/src/content/docs/getting-started.mdx`)


title: Getting started group: Start here order: 1

import Step from '../../components/docs/Step.astro';
import Callout from '../../components/docs/Callout.astro';
import LiveExample from '../../components/LiveExample.astro';

export const data = {
labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'],
series: [
[12, 9, 7, 8, 5],
[2, 1, 3.5, 7, 3]
]
};

**Works without a bundler.** Chartist ships as a native ES module, so a `