Svelte Charts: Quick Charts in SvelteKit with Chart.js
Tags: webdev, css, javascript, svelte
Published: 2022-08-03 09:28:33

---
title: "Svelte Charts: Quick Charts in SvelteKit with Chart.js"
published: "true"
description: "Svelte Charts: how quickly and easily you can add customised charts to your SvelteKit, Astro or other Svelte apps with Chart.js."
tags: "webdev, css, javascript, svelte"
canonical_url: "https://rodneylab.com/svelte-charts/"
cover_image: "https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bh5luee9x0v8nc695sbj.png"
---

## 📊 Svelte Charts with Chart.js

In this Svelte charts post post, we see how you can quickly add **customisable** charts to your Svelte app using Chart.js.  You should find this post useful, in fact, if you are creating a **dashboard** or console and need to throw in some charts.  Alternatively, you might be writing an article **summarising some data**.  You should find the post equally useful for these use cases and many others. Although we focus on **SvelteKit**, we have tested the approach on **Astro** and it should be easily adapted to **other Svelte frameworks**.

## 🧱 What we&rsquo;re Building

We will create a bar chart from the <a href="https://2021.stateofjs.com/en-US/libraries/back-end-frameworks">State of JS 2021</a> survey results.  Locally, we will source the data from a JSON file.  After importing the data, we will then add some custom styling and see configuration changes which you need for Chart.js to work smoothly with SvelteKit.  You will see that with minimal effort you can knock up something with Chart.js and Svelte which does not look too bad at all!

![Svelte Charts: Building: screenshot shows large bar chart with title, colours bars of varying tones, number scale on y axis and labels on x axis.](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/00npaypr5uf85p5r00qe.png)

## 🚀 Quick Start

There&rsquo;s not all that much to do.  You will probably find you spend most time on customising the charts to show your research or data in its best light.  To get going why don&rsquo;t we spin up a new SvelteKit project from the Terminal:

```shell
pnpm create svelte svelte-charts && cd $_
pnpm install
pnpn run dev
```

I chose the **TypeScript** option along with **ESLint** and **Prettier**, but no Browser testing.  If this is your first time using TypeScript with SvelteKit, then you might want to <a aria-label="Open the Starting out Svelte tutorial" href="https://plus.rodneylab.com/tutorials/starting-out-svelte-sveltekit">check out the Starting out Svelte and SvelteKit tutorial</a> which gives a little more colour on using SvelteKit with TypeScript.  We use the Merriweather font self-hosted below, so you might also want to install that now, along with the Chart.js package (and its types):

```shell
pnpm add -D @fontsource/merriweather @types/chart.js chart.js
```

## ⚙️ Svelte Charts: JSON Data

Probably the most important part of this project are the data!  We will add them in a JSON file, then use Vite&rsquo;s JSON import feature to import them onto our chart page.  Create a new `src/lib/data` folder and in there, make a `satisfaction.json` file and past in this content:

```json
{
  "FY2021": [
    { "framework": "SvelteKit", "score": 96 },
    { "framework": "Astro", "score": 91 },
    { "framework": "Fastify", "score": 91 },
    { "framework": "Next.js", "score": 91 },
    { "framework": "Remix", "score": 91 },
    { "framework": "Express", "score": 88 },
    { "framework": "Nest", "score": 85 },
    { "framework": "Eleventy", "score": 82 },
    { "framework": "Nuxt", "score": 82 },
    { "framework": "Strapi", "score": 76 },
    { "framework": "Blitz", "score": 67 },
    { "framework": "Redwood", "score": 67 },
    { "framework": "Gatsby", "score": 51 }
  ]
}
```

## First Try

Chart.js uses an HTML canvas element to create the chart in.  Typically you can just create a div with an `id` and use JavaScript to find that `id` and attach the chart.  However, Svelte lets us bind elements to JavaScript variables, so we will use that approach.  Replace the code in `src/routes/index.svelte` with the following:

```svelte
<script lang="ts">
  import { browser } from '$app/env';
  import { FY2021 as satisfactionData2021 } from '$lib/data/satisfaction.json';
  import '@fontsource/merriweather';
  import { Chart, registerables } from 'chart.js';
  import { onMount } from 'svelte';

  Chart.register(...registerables);

  let barChartElement: HTMLCanvasElement;

  const chartData = {
    labels: satisfactionData2021.map(({ framework }) => framework),
    datasets: [
      {
        label: 'Satisfaction (%)',
        data: satisfactionData2021.map(({ score }) => score),
        backgroundColor: [
          'hsl(347 38% 49%)',
          'hsl(346 65% 63%)',
          'hsl(346 49% 56%)',
          'hsl(346 89% 70%)',
          'hsl(346 90% 76%)',
          'hsl(346 90% 73%)',
          'hsl(346 89% 79%)',
          'hsl(346 89% 85%)',
          'hsl(347 89% 82%)',
          'hsl(346 90% 88%)',
          'hsl(347 87% 94%)',
          'hsl(347 91% 91%)',
          'hsl(346 87% 97%)',
        ],
        borderColor: ['hsl(43 100% 52%)'],
        borderRadius: 4,
        borderWidth: 2,
      },
    ],
  };

  onMount(() => {
    if (browser) {
      new Chart(barChartElement, {
        type: 'bar',
        data: chartData,
        options: {
          plugins: {
            legend: {
              display: false,
            },
          },
          scales: {
            x: {
              grid: {
                color: 'hsl(43 100% 52% / 10%)',
              },
              ticks: { color: 'hsl(43 100% 52% )' },
            },
            y: {
              beginAtZero: false,
              ticks: { color: 'hsl(43 100% 52% )', font: { size: 18 } },
              grid: {
                color: 'hsl(43 100% 52% / 40%)',
              },
              title: {
                display: true,
                text: 'Satisfaction (%)',
                color: 'hsl(43 100% 52% )',
                font: { size: 24, family: 'Merriweather' },
              },
            },
          },
        },
      });
    }
  });
</script>

<main class="main-container">
  <h1>State of JS 2021 Backend Framework Satisfaction</h1>
  <section>
    <canvas bind:this={barChartElement} />
  </section>
</main>
```

This will **not work** out-of-the-box, so let&rsquo;s first see how to fix it then take a closer look at the code.

### Using Chart.js with SvelteKit

You will probably get a `registerables is not iterable` error in your browser.  This is just because although Chart.js ships with ESM support it does not currently work out-of-the-box with SvelteKit. No sweat though, we can <a aria-label="SvelteKit docs on fixing E S M issues" href="https://kit.svelte.dev/faq#packages">fix this with a few lines of config</a>.


Add vite SSR config  `svelte.config.js` to sort this issue:

```javascript
import adapter from '@sveltejs/adapter-auto';
import preprocess from 'svelte-preprocess';

/** @type {import('@sveltejs/kit').Config} */
const config = {
  // Consult https://github.com/sveltejs/svelte-preprocess
  // for more information about preprocessors
  preprocess: preprocess(),

  kit: {
    adapter: adapter(),
    vite: {
      ssr: {
        noExternal: ['chart.js'],
      },
    },
  },
};

export default config;
```

Give that a save then jump back to you browser and it should all be right as rain.


## 👀 A Closer Look at the Code

In line `3` of `src/routes/indx.svelte` we import the top level JSON data as a named import.  If you didn&rsquo;t know you could do this with Vite or SvelteKit, check out the <a aria-label="Open video on using JSON imports in Svelte Kit" href="https://rodneylab.com/sveltekit-json-import/"> short video on Svelte JSON imports</a>.

Jumping down to line `81` we see where we include the chart in our markup.  Adding `bind:this` on the `canvas` element lets us bind our element to a JavaScript variable.  We declare that variable in line `10`.

In lines `12`&ndash;`38` we get our data into a format which Chart.js expects.  As examples, `labels` (line `13`) is just an array of text labels for each data point.  We create it using the JavaScript map method to extract just the `framework` field from each data point in our input JSON.  We do something very similar in line `17` to extract the actual value for each data point.  Then, `backgroundColor` is just an array of colours to use for the bars.  I generated some tints and shades using the What-a-colour app.  You can create and <a aria-label="Read more about the Starting out Svelte and Svelte Kit tutorial" href="https://plus.rodneylab.com/tutorials/starting-out-svelte-sveltekit">customise this app yourself in the Starting out Svelte and SvelteKit tutorial</a>. We also look at converting colours between hex and hsl and generating contrast ratios for a chosen colour palette.


### Chart.js Initialisation

The Svelte `onMount` method is for any setting up we need to do after the initial render of our page.  That works here because we need an initial render in order to have a the `canvas` element to attach the chart to.  In line `43`, we create a Chart object, attaching it to `barChartElement` (our `canvas` element). We add minimal customisation in the following lines.  This is just to give you a flavour of what is possible.  Go to town on your own app.  You will find a <a aria-label="Open Chart.js docs" href="https://www.chartjs.org/docs/latest/">mountain of material on customisation in the Chart.js docs</a>.


## 💄 Svelte Charts: a Little Style

The chart looks a little plain, albeit with the pink bars!  We will see how to change the chart background colour in a moment.  Before that though, here are some styles for the app itself.  Paste this content at the end of `src/routes/index.svelte`:

```svelte
<style>
  :global(html) {
    background-color: var(--colour-theme);
    font-family: Merriweather;
  }
  :global(h1) {
    color: var(--colour-dark);
    font-size: var(--font-size-6);
  }
  :global(:root) {
    --colour-theme: hsl(43 100% 52%); /* selective yellow */
    --colour-brand: hsl(13 46% 25%); /* irish coffee */
    --colour-alt: hsl(346 89% 70%); /* froly */
    --colour-light: hsl(75 100% 98%); /* ceramic */
    --colour-dark: hsl(182 83% 9%); /* tiber */

    --spacing-12: 3rem;
    --spacing-18: 4.5rem;

    --max-width-wrapper: 48rem;

    --font-size-6: 3.052rem;
  }
  .main-container {
    width: min(100% - var(--spacing-12), var(--max-width-wrapper));
    margin: var(--spacing-18) auto;
  }
</style>
```

As a final step we will see how to change the chart background colour, then the customary test!

## 🎨 Svelte Charts: Changing Background Colour

For Chart.js charts, you can change the background colour by updating the canvas element&rsquo;s background.  You could push the boat out and add a picture for the background by tweaking the method we use here.  We will keep it simple though and go for a solid colour.  To do that we create a Chart.js plugin.  Although that sounds overwhelming, it reality it&rsquo;s just a few extra lines of code.

Update `src/lib/routes/index.svelte`:

```svelte
  onMount(() => {
    if (browser) {
      chart = new Chart(barChartElement, {
        type: 'bar',
        data: chartData,
        plugins: [
          {
            id: 'custom_canvas_background_colour',
            beforeDraw: (chart: Chart) => {
              const ctx = chart.canvas.getContext('2d');
              if (ctx) {
                ctx.save();
                ctx.globalCompositeOperation = 'destination-over';
                ctx.fillStyle = 'hsl(13 46% 25%)';
                ctx.fillRect(0, 0, chart.width, chart.height);
                ctx.restore();
              }
            },
          },
        ],
        options: {
          plugins: {
            legend: {
              display: false,
            },
          },
          scales: {
            x: {
              grid: {
                color: 'hsl(43 100% 52% / 10%)',
              },
              ticks: { color: 'hsl(43 100% 52% )' },
            },
            y: {
              beginAtZero: false,
              ticks: { color: 'hsl(43 100% 52% )', font: { size: 18 } },
              grid: {
                color: 'hsl(43 100% 52% / 40%)',
              },
              title: {
                display: true,
                text: 'Satisfaction (%)',
                color: 'hsl(43 100% 52% )',
                font: { size: 24, family: 'Merriweather' },
              },
            },
          },
        },
      });
    }
  });
```

We actually set the background colour to &ldquo;Irish Coffee&rdquo; using HSL in line `53`. That&rsquo;s all there is to creating a chart in Svelte using Chart.js.

## 💯 SvelteCharts: Testing it Out

Hope you are as impressed as I am with how little effort we needed to create something fairly respectable.

## 🙌🏽 Svelte Charts: Wrapup

In this Svelte Charts post we have seen how quickly to create charts in Svelte.  In particular we have touched on:

- using **Chart.js with Svelte** including initialising a chart and **customising styles**,
- adding a **background colour** to a Chart.js bar chart,
- **Vite configuration** for using **Chart.js with SvelteKit**.

This has just been an introduction with using Svelte with Chart.js.  You can use the code here as a stepping stone for creating Svelte Pie Charts, Line Charts and so much more.  Check Chart.js docs for more on the config for these other chart types, then just drop it into your Svelte code.  Let me know what you end up creating.  You can drop a comment below or reach out for a chat on <a aria-label="Jump into the Element Matrix chat room" href="https://matrix.to/#/%23rodney:matrix.org">Element</a> as well as <a aria-label="Mention on Twitter" href="https://twitter.com/intent/user?screen_name=@askRodney">Twitter @mention</a>

You can see the full code for this Svelte Chart project, in all its glory <a aria-label="Open the Rodney Lab Git Hub repo" href="https://github.com/rodneylab/svelte-chartjs" rel="follow noopener noreferrer">in the Rodney Lab Git Hub repo</a>.

## 🙏🏽 Svelte Charts: Feedback

If you have found this video useful, see links below for further related content on this site. I do hope you learned one new thing from the video. Let me know if there are any ways I can improve on it. I hope you will use the code or starter in your own projects. Be sure to share your work on Twitter, giving me a mention so I can see what you did. Finally be sure to let me know ideas for other short videos you would like to see. Read on to find ways to get in touch, further below. If you have found this post useful, even though you can only afford even a tiny contribution, please <a aria-label="Support Rodney Lab via Buy me a Coffee" href="https://rodneylab.com/giving/">consider supporting me through Buy me a Coffee</a>.

Finally, feel free to share the post on your social media accounts for all your followers who will find it useful. As well as leaving a comment below, you can get in touch via <a aria-label="Reach out on Twitter" href="https://twitter.com/messages/compose?recipient_id=1323579817258831875">@askRodney</a> on Twitter and also <a aria-label="Contact Rodney Lab via Telegram" href="https://t.me/askRodney">askRodney on Telegram</a>. Also, see <a aria-label="Get in touch with Rodney Lab" href="https://rodneylab.com/contact">further ways to get in touch with Rodney Lab</a>. I post regularly on <a aria-label="See posts on svelte kit" href="https://rodneylab.com/tags/sveltekit/">SvelteKit</a> as well as <a href="https://rodneylab.com/tags/seo" aria-label="See posts on search engine optimisation">Search Engine Optimisation</a> among other topics. Also <a aria-label="Subscribe to the Rodney Lab newsletter" href="https://rodneylab.com/about/#newsletter">subscribe to the newsletter to keep up-to-date</a> with our latest projects.