Highcharts and Angular: start with one HTML file

Highcharts is a JavaScript charting library, and Angular is only one place to use it. The chart is an options object, so you can build it in a single HTML file first and carry it into an Angular project later.

Highcharts is a JavaScript charting library, and "Highcharts Angular" is its official wrapper for Angular projects. The chart itself does not need Angular. A script tag, a <div> and one call to Highcharts.chart() draw it in a plain HTML file.

Try it. This is the whole file, and the chart is live.

Live exampletry it here, then copy the code
Share it as a link
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Highcharts in one file</title>
<style>
  body { margin: 0; padding: 12px; font-family: system-ui, sans-serif; background: #fff; }
  #chart { width: 100%; height: 320px; }  /* the chart fills this box */
</style>
</head>
<body>
<div id="chart"></div>

<!-- 1. load the library first (pinned version) -->
<script src="https://cdn.jsdelivr.net/npm/highcharts@13.1.1/highcharts.js"></script>
<script>
  // 2. the options object: this is the part you reuse in any framework
  const options = {
    chart: { type: 'line' },
    title: { text: 'Visits per weekday' },
    xAxis: { categories: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'] },
    yAxis: { title: { text: 'Visits' } },
    series: [{ name: 'This week', data: [120, 180, 150, 210, 260] }]
  };

  // 3. draw it into the div with id="chart"
  Highcharts.chart('chart', options);
</script>
</body>
</html>
A complete Highcharts page: one script tag, one div, one call. Edit the numbers and the example reruns.

Build the chart this way first. When it looks right, the options object moves into Angular unchanged.

Where Angular fits in

Angular is a framework that compiles your app with a build step. The Highcharts wrapper for it, highcharts-angular, is installed with npm and used inside Angular components.

A plain HTML file has no build step. It loads the library with a script tag and runs it directly.

Two ways to run the same chart: an Angular project with a build, or one HTML file. The options object is shared.
Two ways to run the same chart: an Angular project with a build, or one HTML file. The options object is shared.

The part that is identical in both is the options object: title, axes and series. That is why a single file is a good place to design the chart.

The three parts of a chart

Every Highcharts page in a single file has the same three parts.

  1. A container. A <div> with an id. The chart is drawn inside it.
  2. The library. A <script src="...highcharts.js"> tag.
  3. A call. Highcharts.chart('chart', options), where the first argument is the container's id.

The options object describes everything else. title.text sets the heading, xAxis.categories the labels along the bottom, and series an array of data sets, each with a name and a data array.

Try another chart type

The chart type is one option, chart.type. The same series can be a line, a column, a bar or an area. In the example below, a button calls chart.update(), which changes an option on the chart that is already on screen and redraws it.

Live exampletry it here, then copy the code
Share it as a link
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Same data, different chart type</title>
<style>
  body { margin: 0; padding: 12px; font-family: system-ui, sans-serif; background: #fff; }
  .bar { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 8px; }
  button {
    font: inherit; padding: 6px 12px; border: 1px solid #c7ccd4; border-radius: 8px;
    background: #f6f7f9; cursor: pointer;
  }
  button[aria-pressed="true"] { background: #1d4ed8; border-color: #1d4ed8; color: #fff; }
  #chart { width: 100%; height: 320px; }
</style>
</head>
<body>
<div class="bar" id="bar">
  <button data-type="line" aria-pressed="true">line</button>
  <button data-type="column" aria-pressed="false">column</button>
  <button data-type="bar" aria-pressed="false">bar</button>
  <button data-type="area" aria-pressed="false">area</button>
</div>
<div id="chart"></div>

<script src="https://cdn.jsdelivr.net/npm/highcharts@13.1.1/highcharts.js"></script>
<script>
  const chart = Highcharts.chart('chart', {
    chart: { type: 'line' },
    title: { text: 'Orders per month' },
    xAxis: { categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'] },
    yAxis: { title: { text: 'Orders' } },
    series: [{ name: '2026', data: [32, 41, 38, 55, 62, 70] }]
  });

  // chart.update() changes an option on the live chart and redraws it
  document.getElementById('bar').addEventListener('click', (e) => {
    const btn = e.target.closest('button');
    if (!btn) return;
    chart.update({ chart: { type: btn.dataset.type } });
    document.querySelectorAll('#bar button').forEach((b) =>
      b.setAttribute('aria-pressed', String(b === btn)));
  });
</script>
</body>
</html>
The same six numbers as a line, column, bar or area chart. Each button changes chart.type.

You do not rebuild the chart or touch the data. Only one option changes.

The script order mistake

A script runs the moment the browser reaches it. If your code calls Highcharts.chart() before the library's script tag, Highcharts does not exist yet, and the console shows a ReferenceError.

The library tag must come before the code that calls it.
The library tag must come before the code that calls it.

Put the library tag first, then your code. The code must also come after the container div, or sit inside a DOMContentLoaded listener the way the Highcharts docs do. Otherwise Highcharts cannot find the element and reports error 13, "Rendering div not found".

Load the library only once. Including it twice produces error 16, "Highcharts already defined in the page".

Give the container a height

A chart is drawn inside its container, and the height comes from the container too. When the option chart.height is left empty, Highcharts uses the container's height, or 400 pixels if that height is 0.

With a height on the div the chart uses it. With none, the chart falls back to 400 pixels.
With a height on the div the chart uses it. With none, the chart falls back to 400 pixels.

Set a height on the div, as the examples do with height: 320px. Then the chart is the size you chose on a laptop and on a phone.

Move the same options into Angular

This part needs Node, npm and an Angular build, so it does not run in a plain HTML file. It is shown here so you can see what carries over.

The Highcharts Angular README installs the wrapper and the library together:

npm install highcharts-angular highcharts --save

Then register it once in app.config.ts:

import { provideHighcharts } from 'highcharts-angular';

export const appConfig: ApplicationConfig = {
  providers: [provideHighcharts()],
};

In a component, the options object is bound to a div with the highchartsChart directive:

import { Component } from '@angular/core';
import { HighchartsChartDirective } from 'highcharts-angular';

@Component({
  template: '<div highchartsChart [options]="chartOptions" class="chart"></div>',
  styles: ['.chart { width: 100%; height: 400px; display: block; }'],
  imports: [HighchartsChartDirective],
})
export class AppComponent {
  chartOptions: Highcharts.Options = {
    series: [{ type: 'line', data: [1, 2, 3] }],
  };
}

Paste the options you tuned in the HTML file into chartOptions. The container still needs a width and a height in CSS, as in the styles line above.

According to the package metadata on npm, the current wrapper expects Angular 19 or newer and Highcharts 12.2 or newer.

A finished example: chart the numbers you paste

This page adds three things to the basics. A form takes label, number lines and redraws the chart on submit. The same numbers appear in a table under the chart. And a second script tag loads the Highcharts accessibility module.

Live exampletry it here, then copy the code
Share it as a link
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Chart from pasted numbers</title>
<style>
  body { margin: 0; padding: 12px; font-family: system-ui, sans-serif; background: #fff; color: #1d2330; }
  h1 { font-size: 18px; margin: 0 0 8px; }
  form { display: grid; gap: 8px; margin-bottom: 10px; }
  textarea {
    font: 14px/1.4 ui-monospace, Consolas, monospace; padding: 8px; height: 96px;
    border: 1px solid #c7ccd4; border-radius: 8px; resize: vertical;
  }
  button {
    font: inherit; padding: 8px 14px; border: 0; border-radius: 8px;
    background: #1d4ed8; color: #fff; cursor: pointer; justify-self: start;
  }
  #msg { font-size: 13px; color: #9a3412; min-height: 18px; }
  #chart { width: 100%; height: 280px; }
  table { border-collapse: collapse; width: 100%; font-size: 14px; margin-top: 8px; }
  th, td { border-bottom: 1px solid #e1e4ea; padding: 4px 8px; text-align: left; }
  td:last-child, th:last-child { text-align: right; }
</style>
</head>
<body>
<h1>Paste "label, number" lines</h1>
<form id="form">
  <textarea id="data" aria-label="Data, one label and number per line">Q1, 120
Q2, 150
Q3, 90
Q4, 210</textarea>
  <button type="submit">Draw chart</button>
  <div id="msg" role="status"></div>
</form>

<div id="chart"></div>
<table id="tbl"><thead><tr><th>Label</th><th>Value</th></tr></thead><tbody></tbody></table>

<script src="https://cdn.jsdelivr.net/npm/highcharts@13.1.1/highcharts.js"></script>
<script src="https://cdn.jsdelivr.net/npm/highcharts@13.1.1/modules/accessibility.js"></script>
<script>
  const msg = document.getElementById('msg');

  function parse(text) {
    const rows = [];
    for (const line of text.split('\n')) {
      if (!line.trim()) continue;
      const i = line.lastIndexOf(',');
      const value = Number(line.slice(i + 1));
      if (i < 1 || !Number.isFinite(value)) throw new Error('Bad line: "' + line.trim() + '"');
      rows.push([line.slice(0, i).trim(), value]);
    }
    if (!rows.length) throw new Error('Add at least one line.');
    return rows;
  }

  function draw(rows) {
    Highcharts.chart('chart', {
      chart: { type: 'column' },
      title: { text: 'Your numbers' },
      xAxis: { categories: rows.map((r) => r[0]) },
      yAxis: { title: { text: 'Value' } },
      legend: { enabled: false },
      series: [{ name: 'Value', data: rows.map((r) => r[1]) }]
    });
    // the same numbers as a table: readable without the chart and easy to copy
    document.querySelector('#tbl tbody').innerHTML = rows
      .map((r) => '<tr><td></td><td>' + r[1] + '</td></tr>').join('');
    document.querySelectorAll('#tbl tbody tr').forEach((tr, n) => {
      tr.firstChild.textContent = rows[n][0];  // textContent: table cells never parse pasted text as HTML
    });
  }

  document.getElementById('form').addEventListener('submit', (e) => {
    e.preventDefault();  // handled inside the page, nothing is sent anywhere
    try {
      draw(parse(document.getElementById('data').value));
      msg.textContent = '';
    } catch (err) {
      msg.textContent = err.message;
    }
  });

  draw(parse(document.getElementById('data').value));
</script>
</body>
</html>
Paste label and number lines, press Draw chart. The form is handled inside the page and nothing is sent anywhere.
  • The form stays in the page. The submit listener calls preventDefault(), reads the textarea and draws the chart.
  • A table sits under the chart. Anyone can read or copy the figures without hovering.
  • The accessibility module is a separate file. The Highcharts docs say it is not included by default and recommend adding it.

For charts with no library at all, see a line chart in plain SVG and a bar chart from a table.

Licence and CDN: read before you publish

Highcharts may need a licence, depending on how you use it. The header of the library file says "A commercial license may be required depending on use" and points to the licence page on highcharts.com.

Check that page for your case before putting a chart on a public site.

The examples load the library from jsDelivr with a pinned version, 13.1.1. The Highcharts docs say a CDN suits demos, prototypes and simple static pages. For production they suggest npm or self-hosted files.

When it does not work

Symptom Cause Fix
Blank area, console says Highcharts is not defined The library tag is missing, blocked, or after your code Put the highcharts.js tag first
Error 13, Rendering div not found The id in the call matches no element, or the code runs before the div Match the id, and place the script after the div
Error 16, Highcharts already defined The library is included twice Include it once
Chart is 400 pixels tall when you wanted less The container has no height Give the div an explicit height
Chart works in a file but not in Angular The npm packages or provideHighcharts() are missing Install both packages and register the provider
A button or module does nothing Its script file is missing Load the module file after highcharts.js
Nothing at all, no console message JavaScript did not run See JavaScript not working in HTML

A chart is better shown than described. A screenshot loses the hover labels and the buttons, and an attached .html file may open as plain code on a phone. Sharing an interactive chart covers what survives on a small screen.

To send the working version, paste the page into a NOS document and choose Create share link. HTML to link walks through it. The page renders as written and its scripts run, including the Highcharts file from jsDelivr.

The people you send it to can switch the chart type and paste numbers themselves. If you change the code later, the same link shows the new version.

Questions people ask

Can I use Highcharts without Angular?

Yes. Highcharts is a plain JavaScript library. Load highcharts.js with a script tag, add a div, and call Highcharts.chart() with an options object. Angular is one way to use it, through the highcharts-angular wrapper, not a requirement.

How do I use Highcharts in an Angular project?

Install the official wrapper and the library with npm install highcharts-angular highcharts, add provideHighcharts() to app.config.ts, and put a div with the highchartsChart directive and an options binding in a component. That needs Node, npm and a build, so it does not run in a plain HTML file.

Do I need a licence for Highcharts?

It depends on how you use it. The header of the library file says a commercial licence may be required depending on use, and points to the licence page on highcharts.com. Read that page before you publish a chart on a public site.

Why does my Highcharts chart not appear?

Three causes cover most cases: the script tag for highcharts.js comes after your code, the id you pass to Highcharts.chart() does not match any element, or the library file failed to load. Open the browser console and read the first error.

Is it fine to load Highcharts from a CDN?

The Highcharts docs describe a CDN as useful for demos, prototypes and simple static pages, and say npm or self-hosted files are usually a better long-term choice for production. They also ask you to follow the Highsoft fair usage policy.

Keep reading