Setup and configuration

Create a chart from a canvas, understand the three-part config object, and register only the pieces you actually use.

Create a chart

<div style="position: relative; height: 320px;">
  <canvas id="sales"></canvas>
</div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/chart.umd.min.js"></script>
<script>
  const ctx = document.getElementById('sales');
  const chart = new Chart(ctx, {
    type: 'bar',
    data: {
      labels: ['Jan', 'Feb', 'Mar', 'Apr'],
      datasets: [{ label: 'Units', data: [12, 19, 8, 15], backgroundColor: '#4f46e5' }]
    },
    options: { responsive: true, maintainAspectRatio: false }
  });
</script>
ApproachLoadWhen it fits
UMD script tagOne global ChartStatic pages and quick experiments
npm i chart.js + chart.js/autoImports and registers everythingApps where bundle size is not critical
Named imports + Chart.register()Only the parts you listProduction bundles where every KB counts
Wrapper packagesReact/Vue/Svelte componentsWhen you want lifecycle handling done for you
npm install chart.js
# optional, for a real time axis
npm install chartjs-adapter-date-fns date-fns

The config object

Every chart is described by three keys: type chooses the controller, data holds labels, datasets and their styling, and options holds everything that is not data — scales, plugins, animation and interaction.

const config = {
  type: 'line',
  data: {
    labels: ['Q1', 'Q2', 'Q3'],
    datasets: [{
      label: 'Revenue',
      data: [30, 45, 60],
      borderColor: '#0ea5e9',
      backgroundColor: 'rgba(14, 165, 233, 0.15)',
      fill: true,
      tension: 0.35
    }]
  },
  options: {
    responsive: true,
    interaction: { mode: 'index', intersect: false },
    scales: {
      y: { beginAtZero: true, title: { display: true, text: 'thousands' } }
    },
    plugins: {
      legend: { position: 'bottom' },
      tooltip: { enabled: true }
    }
  }
};
new Chart(document.getElementById('sales'), config);
  • Chart type defaults live on Chart.overrides.bar (and the other controllers) and can be changed globally.
  • Global styling defaults sit under Chart.defaults — for example Chart.defaults.font.family.
  • Anything set on a dataset wins over the controller override, which wins over the global default.

Registering only what you use

// full auto-registration: simplest, largest bundle
import Chart from 'chart.js/auto';

// explicit: bundle only these six pieces for one line chart
import {
  Chart, LineController, LineElement, PointElement,
  LinearScale, CategoryScale, Title, Tooltip, Legend, Filler
} from 'chart.js';

Chart.register(
  LineController, LineElement, PointElement,
  LinearScale, CategoryScale, Title, Tooltip, Legend, Filler
);

export default new Chart(canvas, config);
You wantRegister
BarsBarController, BarElement
Lines with pointsLineController, LineElement, PointElement
Filled areasFiller
Pie or doughnutPieController or DoughnutController, plus ArcElement
RadarRadarController, RadialLinearScale
Numeric axesLinearScale; categories use CategoryScale
A time axisTimeScale and a date adapter package
⚠️
Forgetting a registration produces the "is not a registered controller/scale" error at runtime rather than a build error. When a chart fails in production but works locally, check that the tree-shaken build registers every element the config uses.

FAQ

Why does my canvas keep growing in height?
Chart.js resizes the canvas to its parent. With maintainAspectRatio: false the parent needs a fixed or constrained height, otherwise each resize pass makes the canvas taller. Wrap it in a positioned container with an explicit height.
Can I build the chart without a canvas element?
Yes — create one in memory with document.createElement('canvas') and pass it to new Chart(). This is how you render charts for export or for offscreen use.

Chart types and datasets Option configuration

Last refreshed 2026-09-18.