# Getting started

> WestCoast Charts 1.1.5, release, public Core release, on npm. HTML: https://westcoast-charts.com/docs/getting-started/ · Index for agents: https://westcoast-charts.com/llms.txt · Source: library guide, commit 95f093ba

WestCoast Charts draws interactive SVG charts for dashboards and web apps.

- [Install](#install)
- [Your first chart](#your-first-chart)
- [Entries: core, types, features, premium](#entries-core-types-features-premium)
- [ES modules, CommonJS and script tags](#es-modules-commonjs-and-script-tags)
- [Frameworks: React, Vue, Svelte, Angular](#frameworks)
- [Server-side rendering](#server-side-rendering)
- [TypeScript](#typescript)
- [Content Security Policy](#content-security-policy)

## Install

Install the [Free Core](https://westcoast-charts.com/download/) for version 1.1.5. It includes the MIT Core and the Full Free bundle, all free chart types and features, optional validation/describe helpers and schemas. No account, payment or licence key is required. Premium is supplied separately through the [30-day trial or a paid licence](https://westcoast-charts.com/pricing/); its imports require that separately supplied complete package.

### Start with Core; add only the extras you need

For a basic line, bar or pie chart, start with the standard Core entry. Full Free also loads all free optional types and features. Install the pinned version, then import Core:

```sh
npm install west-coast-charts@1.1.5
```

```js
import WestCoastCharts from 'west-coast-charts'

const chart = new WestCoastCharts(document.querySelector('#chart'), {
  chart: { type: 'line', height: 320 },
  series: [{ name: 'Requests', data: [12, 19, 15] }],
  xaxis: { categories: ['09:00', '10:00', '11:00'] }
})
await chart.render()
```

For an optional type, register its module before rendering. A dynamic import can defer it until its view opens:

```js
async function showGauge(element, options) {
  const { default: gauge } = await import('west-coast-charts/types/gauge')
  WestCoastCharts.use(gauge)
  const chart = new WestCoastCharts(element, options)
  await chart.render()
  return chart
}
```

| Released browser build | File | Gzip level 9 |
| --- | --- | ---: |
| Standard Core | `west-coast-charts.min.js` | 194,836 B |
| Extra types | `west-coast-charts-types.min.js` | 83,472 B |
| Full Free | `west-coast-charts.full.min.js` | 380,285 B |

These sizes describe compressed artifacts, not a loading-time or interaction-speed guarantee. Core already contains the standard renderers; `/core` aliases the normal entry, so selective optional imports do not remove that baseline. Extra types is an optional module, not another complete Core bundle. Shared runtime code contributes to each optional type's actual cost. See [measured consumer sizes for every optional type and the reproducible method](https://westcoast-charts.com/docs/loading/).

[Heatmap row order and Gauge option conventions](https://westcoast-charts.com/docs/chart-conventions/) explain two configuration choices before you use them.

## Public Core distribution

- [Public Core repository](https://github.com/Lokumbus/west-coast-charts-core) and [versioned package](https://github.com/Lokumbus/west-coast-charts-core/releases/download/v1.1.5/west-coast-charts-1.1.5.tgz). MIT; no account or key required. Premium runtimes are excluded.
- Install from npm:

```sh
npm install west-coast-charts@1.1.5
```

- Archive SHA-256: `c4a4fdfebe81f29ad27b6e583e3a343e79e93633f54208f0c26a6d586a577dcc`.
- [Pinned browser CDN bundle](https://cdn.jsdelivr.net/npm/west-coast-charts@1.1.5/dist/west-coast-charts.full.min.js). Load it as a script tag, without a bundler. Use the release tag, not an unversioned latest URL.
- Core includes optional `agent/validate`, `agent/describe` and versioned JSON schemas. Install and register these modules explicitly when using the lean Core entry.
- A cloud workspace restricted to GitHub and npm can install the GitHub archive. Its artifact viewer may have a separate network allowlist: bundle the installed library into the artifact if it cannot load the CDN. Publishing a package cannot override a client's network policy.

### Offline archives

- [Core ZIP](https://westcoast-charts.com/downloads/west-coast-charts-1.1.5.zip): unzip it and open example.html for an offline browser example.
- [Core npm archive](https://westcoast-charts.com/downloads/west-coast-charts-1.1.5.tgz): install the downloaded file in your application.

```sh
npm install ./west-coast-charts-1.1.5.tgz
```

The command above installs the downloaded file. Use the verified public installation channel above when the website download host is unavailable in your workspace.

For a page without a bundler, copy the ZIP's dist folder alongside your HTML:

```html
<div id="chart"></div>
<script src="./dist/west-coast-charts.full.min.js"></script>
<script>
  new WestCoastCharts(document.querySelector('#chart'), {
    chart: { type: 'bar', height: 300 },
    series: [{ name: 'Deploys', data: [12, 19, 7, 15, 22] }],
    xaxis: { categories: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'] }
  }).render()
</script>
```

The Full Free bundle includes the free plugins. With the lean Core entry, register only the additional types and features your application needs, as shown below. The library injects its stylesheet when the first chart renders.

### Browser CDN

Load the versioned Full Free bundle directly. Its Subresource Integrity hash checks the exact bytes; allow cdn.jsdelivr.net in your application's script-src policy if you use it.

```html
<script src="https://cdn.jsdelivr.net/npm/west-coast-charts@1.1.5/dist/west-coast-charts.full.min.js" integrity="sha384-IvVUi5Mw5BSFzQ14ISAoMnSHE1Ot+DIoyMCM5DHL/TEsZuw0l2j5im+MGc7d8C0A" crossorigin="anonymous"></script>
```

If an artifact viewer blocks this CDN, bundle the installed Core into your artifact instead. That viewer's network policy is outside the library's control.

## Your first chart

```js
import WestCoastCharts from 'west-coast-charts'

const chart = new WestCoastCharts(document.querySelector('#chart'), {
  chart: { type: 'line', height: 320 },
  series: [
    { name: 'p95 latency (ms)', data: [210, 198, 240, 380, 260, 220, 205] },
    { name: 'p50 latency (ms)', data: [88, 85, 92, 140, 101, 90, 87] },
  ],
  xaxis: { categories: ['00:00', '04:00', '08:00', '12:00', '16:00', '20:00', '24:00'] },
  title: { text: 'Checkout latency' },
})
await chart.render()

// later: new data animates from the current state
await chart.updateSeries([
  { name: 'p95 latency (ms)', data: [205, 190, 230, 300, 250, 215, 200] },
  { name: 'p50 latency (ms)', data: [86, 84, 90, 120, 98, 88, 86] },
])

// when the element goes away
chart.destroy()
```

Three things every chart needs:

1. **An element.** The chart fills its width; set `chart.height` (or a CSS height on the element).
2. **Options.** `chart.type`, `series` and, for category axes, `xaxis.categories`. The full list is in
   the [options reference](https://westcoast-charts.com/docs/reference/options/index.md).
3. **`render()`.** It returns a promise that resolves once the chart is drawn.

Every chart is accessible without extra work: keyboard navigation, screen-reader descriptions and a
hidden data table are on by default. See [Accessibility reference](https://westcoast-charts.com/docs/accessibility/).

## Entries: core, types, features, premium

The package is split so you only ship what you use.

| Import | What you get | License |
| --- | --- | --- |
| `west-coast-charts` | The core: line, area, bar, pie/donut, radialBar, scatter, bubble, heatmap, candlestick, boxPlot, radar, polarArea, rangeBar, rangeArea, treemap, plus theming, accessibility, animation and export | MIT |
| `west-coast-charts/types` | All additional chart types: gauge, funnel/pyramid, waterfall, dumbbell, histogram, violin/raincloud, sunburst, icicle, streamgraph, unit/waffle, barRace, calendar, slope, beeswarm, nested treemaps, extra theme presets | MIT |
| `west-coast-charts/types/<name>` | One of those types (side-effect import), e.g. `west-coast-charts/types/gauge` | MIT |
| `west-coast-charts/features/<name>` | One optional feature: `drilldown`, `link`, `highlight-filter`, `history`, `narrative`, `perspectives`, `storyboard`, `trellis`, `readability`, `renderer-canvas` | MIT |
| `west-coast-charts/full` | Core + all types + all features in one file | MIT |
| `west-coast-charts/premium` | Premium chart types: sankey, chord, gantt, tree, stock, map, marimekko, network, radialColumn. Needs a licence key in production, see [Premium and licensing](https://westcoast-charts.com/docs/premium/index.md) | Commercial key (code MIT) |

Plugins are installed with `WestCoastCharts.use()`. Installing the same plugin twice does nothing.

```js
import WestCoastCharts from 'west-coast-charts'
import types from 'west-coast-charts/types'

WestCoastCharts.use(types)

const chart = new WestCoastCharts(document.querySelector('#chart'), {
  chart: { type: 'waterfall', height: 300 },
  series: [{ name: 'Monthly cost (EUR)', data: [
    { x: 'Start', y: 4200 }, { x: 'Compute', y: 900 }, { x: 'Storage', y: 250 },
    { x: 'Savings plan', y: -700 }, { x: 'Egress', y: 180 },
  ] }],
})
await chart.render()
```

If a chart uses a type whose entry is not loaded, `render()` rejects with a message that names the
import to add, and the same hint is logged once. Nothing is silently drawn as a different type.

## ES modules, CommonJS and script tags

The package has an `exports` map, so bundlers (Vite, webpack 5, Rollup, esbuild, Parcel) and Node pick
the right file automatically.

| Format | Core | Premium |
| --- | --- | --- |
| ES module (`import`) | `dist/west-coast-charts.esm.js` | `dist/west-coast-charts-premium.esm.js` |
| CommonJS (`require`) | `dist/west-coast-charts.common.js` | `dist/west-coast-charts-premium.common.js` |
| Script tag (UMD, global `WestCoastCharts`) | `dist/west-coast-charts.min.js` (`.js` = unminified) | `dist/west-coast-charts-premium.min.js` (global `WestCoastChartsPremium`) |
| AMD (UMD build) | `dist/west-coast-charts.min.js` (`define.amd` supported) | – |

ES modules:

```js
import WestCoastCharts from 'west-coast-charts'
// the same class under its compatibility name:
import { ApexCharts } from 'west-coast-charts'

console.log(ApexCharts === WestCoastCharts) // true
```

CommonJS:

```js
const WestCoastCharts = require('west-coast-charts')
const premium = require('west-coast-charts/premium')

WestCoastCharts.use(premium)
```

Script tags: plugin bundles loaded after the core install themselves into the global
`WestCoastCharts`. Calling `use()` yourself as well is harmless. Feature bundles
(`dist/features/<name>.min.js`) share a small runtime: load `dist/features/runtime.min.js` once, right
after the core and before the first feature bundle (`west-coast-charts.full.min.js` already contains it).
Bundlers resolve this automatically.

```html
<div id="chart"></div>
<script src="dist/west-coast-charts.min.js"></script>
<script src="dist/west-coast-charts-types.min.js"></script>
<script src="dist/west-coast-charts-premium.min.js"></script>
<script>
  new WestCoastCharts(document.querySelector('#chart'), {
    chart: { type: 'sankey', height: 300 },
    series: [{ data: [
      { from: 'Ingress', to: 'API', value: 70 },
      { from: 'Ingress', to: 'Static', value: 30 },
      { from: 'API', to: 'Postgres', value: 45 },
      { from: 'API', to: 'Cache', value: 25 },
    ] }],
  }).render()
</script>
```

(This page is served from a public host name and has no licence key, so the premium chart shows the
small "unlicensed" line. See [Premium and licensing](https://westcoast-charts.com/docs/premium/index.md).)

## Frameworks

WestCoast Charts has no framework dependency and there are no official wrapper packages yet. A chart
needs three lifecycle steps, which map onto every framework the same way:

| Step | Call |
| --- | --- |
| element is in the DOM | `chart = new WestCoastCharts(el, options); chart.render()` |
| options change | `chart.updateOptions(options)` (or `chart.updateSeries(series)` for data only) |
| element is removed | `chart.destroy()` |

The examples below load the library with a dynamic `import()` inside the mount step. That keeps the
library out of the server bundle in Next.js, Nuxt, SvelteKit and Angular SSR (see
[Server-side rendering](#server-side-rendering)) and splits it into its own chunk. In a client-only app
a normal top-level `import` works just as well.

### React

```jsx
'use client' // Next.js app router: render on the client only
import { useEffect, useRef } from 'react'

export default function Chart({ options }) {
  const el = useRef(null)
  const chart = useRef(null)

  // create once, destroy on unmount
  useEffect(() => {
    let alive = true
    import('west-coast-charts').then(({ default: WestCoastCharts }) => {
      if (!alive) return
      chart.current = new WestCoastCharts(el.current, options)
      chart.current.render()
    })
    return () => {
      alive = false
      chart.current?.destroy()
      chart.current = null
    }
  }, [])

  // later option changes animate the existing chart
  useEffect(() => {
    chart.current?.updateOptions(options)
  }, [options])

  return <div ref={el} />
}
```

Keep `options` stable between renders (`useMemo`, state, or a module constant); a new object on every
render means an update on every render.

### Vue 3

```vue
<script setup>
import { onBeforeUnmount, onMounted, ref, toRaw, watch } from 'vue'

const props = defineProps({ options: { type: Object, required: true } })
const el = ref(null)
let chart = null
let alive = true

onMounted(async () => {
  const { default: WestCoastCharts } = await import('west-coast-charts')
  if (!alive) return
  chart = new WestCoastCharts(el.value, toRaw(props.options))
  chart.render()
})

watch(() => props.options, (options) => chart?.updateOptions(toRaw(options)), { deep: true })

onBeforeUnmount(() => {
  alive = false
  chart?.destroy()
})
</script>

<template>
  <div ref="el" />
</template>
```

### Svelte 5

```svelte
<script>
  import { onMount } from 'svelte'

  let { options } = $props()
  let el
  let chart = $state(null)

  onMount(() => {
    let alive = true
    import('west-coast-charts').then(({ default: WestCoastCharts }) => {
      if (!alive) return
      chart = new WestCoastCharts(el, $state.snapshot(options))
      chart.render()
    })
    return () => {
      alive = false
      chart?.destroy()
    }
  })

  // runs again whenever `options` changes
  let first = true
  $effect(() => {
    const next = $state.snapshot(options)
    if (!chart) return
    if (first) { first = false; return } // the chart was just created with these options
    chart.updateOptions(next)
  })
</script>

<div bind:this={el}></div>
```

### Angular (17+)

```ts
import { Component, ElementRef, Input, OnChanges, OnDestroy, ViewChild, afterNextRender } from '@angular/core'
import type { WestCoastChartsOptions } from 'west-coast-charts'

@Component({
  selector: 'wcc-chart',
  standalone: true,
  template: '<div #host></div>',
})
export class ChartComponent implements OnChanges, OnDestroy {
  @Input({ required: true }) options!: WestCoastChartsOptions
  @ViewChild('host', { static: true }) host!: ElementRef<HTMLDivElement>
  private chart: any = null
  private destroyed = false

  constructor() {
    // afterNextRender runs in the browser only, never during server-side rendering
    afterNextRender(async () => {
      const { default: WestCoastCharts } = await import('west-coast-charts')
      if (this.destroyed) return
      this.chart = new WestCoastCharts(this.host.nativeElement, this.options)
      this.chart.render()
    })
  }

  ngOnChanges(): void {
    this.chart?.updateOptions(this.options)
  }

  ngOnDestroy(): void {
    this.destroyed = true
    this.chart?.destroy()
  }
}
```

For Angular 16 and older, create the chart in `ngAfterViewInit` and guard it with
`isPlatformBrowser(platformId)` when you use server-side rendering.

### Other frameworks

Anything with a "mounted" and an "unmounted" hook works the same way (Solid `onMount`/`onCleanup`, Lit
`firstUpdated`/`disconnectedCallback`, Alpine `x-init`, plain web components `connectedCallback`/
`disconnectedCallback`).

## Server-side rendering

Importing the library on the server is safe: loading it does not touch `window` or `document`, so a
module that imports it can be part of a server bundle (Next.js, Nuxt, SvelteKit, Angular SSR, plain
Node). Drawing a chart still needs a browser DOM. Create charts in a client-only step (`useEffect`,
`onMounted`, `onMount`, `afterNextRender`), as the framework examples above do.

```js
// runs in plain Node: no window, no document
import WestCoastCharts from 'west-coast-charts'

console.log(typeof window)                          // 'undefined'
console.log(WestCoastCharts.escapeHtml('<b>Q1</b>')) // helpers that need no DOM work on the server
```

The dynamic `import()` in the framework examples is therefore not required for correctness; it keeps
the library out of the server bundle and out of the first page load.

Server rendering of charts to static SVG is not part of v1. Calling `new WestCoastCharts(...)` or
`render()` without a DOM fails. Tests and scripts that use a DOM implementation in Node (jsdom,
happy-dom) can create the DOM before or after the import; the chart constructor picks up the current
`window`. Charts measure text and SVG geometry, which those DOM implementations do not provide, so
expect stubs for `getBBox` / `getComputedTextLength` there (the library's own unit tests use the ones
in `tests/unit/__mocks__/SVGGeometry.js`).

## TypeScript

Type declarations ship with the package; there is nothing extra to install.

```ts
import WestCoastCharts, { type WestCoastChartsOptions } from 'west-coast-charts'

const options: WestCoastChartsOptions = {
  chart: { type: 'area', height: 280 },
  series: [{ name: 'CPU %', data: [31, 40, 28, 51, 42, 109, 100] }],
}
new WestCoastCharts(document.getElementById('chart'), options).render()
```

`ApexOptions` and every `Apex*` interface are still exported, so typed code written for ApexCharts
4.x compiles unchanged. Premium options are typed in `west-coast-charts/premium`
(see [Premium options reference](https://westcoast-charts.com/docs/reference/premium-options/index.md)).

## Content Security Policy

- **Styles.** The library injects `<style>` elements. With a nonce-based `style-src`, pass the
  nonce: `chart: { nonce: '...' }`. The charts also set inline `style` attributes, so allow
  `style-src-attr 'unsafe-inline'`.
- **Trusted Types.** Pages that enforce Trusted Types must allow the policy name `west-coast-charts`.
- **PNG export.** Rasterising uses a `blob:` URL and falls back to `data:`; `img-src` must allow one of
  them for PNG export.

More in [Performance and security](https://westcoast-charts.com/docs/performance-and-security/index.md#security).

## Next steps

- [Migrating from ApexCharts 4.x](https://westcoast-charts.com/docs/migration-from-apexcharts/index.md)
- [Premium and licensing](https://westcoast-charts.com/docs/premium/index.md) and the [radial column guide](https://westcoast-charts.com/docs/radial-column/index.md)
- [Options reference](https://westcoast-charts.com/docs/reference/options/index.md) and [methods reference](https://westcoast-charts.com/docs/reference/methods/index.md)
- Theming: [Theming and design tokens](https://westcoast-charts.com/docs/theming/) · Accessibility: [Accessibility reference](https://westcoast-charts.com/docs/accessibility/)
