keystone-chartjs-vue
v1.0.0
Published
A single, generic <Chart> component for Vue 3 wrapping Chart.js — every built-in chart type plus the financial, boxplot, matrix, sankey, and treemap extensions, selected via a `type` prop.
Maintainers
Keywords
Readme
keystone-chartjs-vue
A single, generic <Chart> component for Vue 3 wrapping Chart.js — every
built-in chart type plus the most popular ecosystem extensions, selected via
a type prop. Zero manual Chart.register(...) calls required.
Installation
npm install keystone-chartjs-vue chart.jschart.js is a peer dependency — install it alongside this package.
Quick start
<script setup lang="ts">
import { Chart } from 'keystone-chartjs-vue';
const data = {
labels: ['Jan', 'Feb', 'Mar'],
datasets: [{ label: 'Revenue', data: [50, 65, 58] }],
};
const options = { responsive: true };
</script>
<template>
<Chart type="bar" :data="data" :options="options" aria-label="Monthly revenue" />
</template>Supported chart kinds
| type value | Kind | Backed by |
|---|---|---|
| bar | Bar (vertical or horizontal via indexAxis: 'y') | Chart.js built-in |
| line | Line / area | Chart.js built-in |
| bubble | Bubble | Chart.js built-in |
| scatter | Scatter | Chart.js built-in |
| doughnut | Doughnut | Chart.js built-in |
| pie | Pie | Chart.js built-in |
| polarArea | Polar area | Chart.js built-in |
| radar | Radar | Chart.js built-in |
| candlestick | Candlestick (OHLC financial) | chartjs-chart-financial |
| ohlc | OHLC bar | chartjs-chart-financial |
| boxplot | Box plot | @sgratzl/chartjs-chart-boxplot |
| violin | Violin plot | @sgratzl/chartjs-chart-boxplot |
| matrix | Matrix / heatmap | chartjs-chart-matrix |
| sankey | Sankey flow diagram | chartjs-chart-sankey |
| treemap | Treemap | chartjs-chart-treemap |
Props
| Prop | Type | Required | Description |
|---|---|---|---|
| type | ChartKind | ✅ | Which chart to render |
| data | ChartConfigData | ✅ | Chart.js dataset configuration |
| options | ChartConfiguration['options'] | — | Chart.js options |
| zoom | ZoomPluginOptions \| boolean | — | Opt in to chartjs-plugin-zoom |
| annotation | AnnotationPluginOptions | — | Opt in to chartjs-plugin-annotation |
| dataLabels | DataLabelsPluginOptions \| boolean | — | Opt in to chartjs-plugin-datalabels |
| gradient | boolean | — | Opt in to chartjs-plugin-gradient (config lives on each dataset) |
| timestack | boolean | — | Opt in to chartjs-scale-timestack (alternative time axis) |
| hierarchical | boolean | — | Opt in to chartjs-plugin-hierarchical (collapsible tree axis) |
| imageLabel | ImageLabelPluginOptions | — | Opt in to chartjs-plugin-image-label (draws an image on each doughnut/pie slice) |
| autocolors | AutocolorsPluginOptions \| boolean | — | Opt in to chartjs-plugin-autocolors (automatically assigns a distinct color per dataset) |
| deferred | DeferredPluginOptions \| boolean | — | Opt in to chartjs-plugin-deferred (defers the chart's initial update until it scrolls into the viewport) |
| trendline | boolean | — | Opt in to chartjs-plugin-trendline (config lives on each dataset) |
| plugins | ChartConfiguration['plugins'] | — | Inline, custom Chart.js plugin objects |
Any attribute that isn't a declared prop (including aria-label, role,
id, class, style) is forwarded directly onto the rendered <canvas>
element via Vue's own attribute-fallthrough behavior.
Slots
| Slot | Description |
|---|---|
| default | Fallback content rendered inside the <canvas> tags — shown by browsers and assistive technology that cannot render canvas at all |
Escape hatch
Access the live Chart.js instance via a template ref:
<script setup lang="ts">
import { ref } from 'vue';
import { Chart } from 'keystone-chartjs-vue';
const chartRef = ref<InstanceType<typeof Chart> | null>(null);
// chartRef.value?.chart — live Chart.js instance after mount
</script>
<template>
<Chart ref="chartRef" type="bar" :data="data" />
</template>Plugins
<!-- Zoom/pan -->
<Chart type="line" :data="data" zoom />
<Chart type="line" :data="data" :zoom="{ zoom: { wheel: { enabled: true } } }" />
<!-- Annotations -->
<Chart type="line" :data="data" :annotation="{ annotations: { line1: { type: 'line', yMin: 50, yMax: 50 } } }" />
<!-- Data labels -->
<Chart type="bar" :data="data" dataLabels />
<!-- Gradient (boolean only — config lives on each dataset, not here) -->
<Chart type="bar" gradient :data="{ datasets: [{ data: [...], gradient: { backgroundColor: { axis: 'y', colors: { 0: 'red', 100: 'green' } } } }] }" />
<!-- Timestack (boolean only — registers via a side-effect import, no Chart.register call) -->
<Chart type="line" timestack :data="{ datasets: [{ data: [{ x: 1735689600000, y: 1 }] }] }" :options="{ scales: { x: { type: 'timestack' } } }" />
<!-- Hierarchical (boolean only — requires this scale's own tree-node data shape) -->
<Chart type="bar" hierarchical :data="{ labels: [{ label: '2024', children: ['Q1', 'Q2'] }], datasets: [{ data: [{ value: 100, children: [40, 60] }] }] }" :options="{ scales: { x: { type: 'hierarchical' } } }" />
<!-- Image label (imagesList is required — no plain-boolean form) -->
<Chart type="doughnut" :image-label="{ imagesList: [{ imageUrl: 'chrome.png', imageWidth: 32, imageHeight: 32 }] }" :data="data" />
<!-- Autocolors (accepts true or a config object, like zoom/dataLabels) -->
<Chart type="line" autocolors :data="data" />
<!-- Deferred (accepts true or a config object, like zoom/dataLabels) -->
<Chart type="bar" :deferred="{ xOffset: 150, yOffset: '50%', delay: 500 }" :data="data" />
<!-- Trendline (boolean only — config lives on each dataset, not here) -->
<Chart type="line" trendline :data="{ datasets: [{ data: [12, 19, 15, 24, 30], trendlineLinear: { colorMin: 'red', colorMax: 'red' } }] }" />
<!-- Custom, inline plugins (any plugin outside the 10 official ones above) -->
<Chart type="bar" :data="data" :plugins="[customPlugin]" />Unlike data/options, changing the plugins array's own reference
forces a destroy-and-reconstruct rather than an in-place update, since
Chart.js only ever reads plugins at construction time.
Mixed charts
<Chart
type="bar"
:data="{
labels: ['Jan', 'Feb', 'Mar'],
datasets: [
{ label: 'Revenue', data: [50, 65, 58] },
{ label: 'Target', data: [55, 60, 62], type: 'line' }
]
}"
/>Documentation
Full guide, API reference, concept pages, and live examples at kcw.winnem.tech.
License
MIT — see LICENSE. Copyright (c) 2025 Geirr Winnem.
