Skip to content

Vue

bash
npm install @chartbuddy.io/embed vue

vue is an optional peer dependency — install it only if you use these bindings. Vue 3.

vue
<script setup>
import { InsightChart } from '@chartbuddy.io/embed/vue';

const chartData = {
  chartType: 'clusteredBar',
  isDataTransposed: true,
  seriesData: [['', 'Q1', 'Q2'], ['Revenue', 100, 112]],
};
</script>

<template>
  <InsightChart :chart-data="chartData" style="height: 400px" />
</template>

The chart fills its container, so give the container a height. A container with no height renders nothing visible.

Without a bundler (CDN / single HTML file)

The bindings import vue as a bare specifier, so a plain HTML page needs an import map. Use the browser ESM build of Vue, and render without SFCs:

html
<script type="importmap">
  {
    "imports": {
      "vue": "https://unpkg.com/vue@3/dist/vue.esm-browser.prod.js",
      "@chartbuddy.io/embed": "https://unpkg.com/@chartbuddy.io/embed",
      "@chartbuddy.io/embed/vue": "https://unpkg.com/@chartbuddy.io/embed/vue.mjs"
    }
  }
</script>

<div id="app"></div>

<script type="module">
  import { createApp, h } from 'vue';
  import { InsightChart } from '@chartbuddy.io/embed/vue';

  const chartData = {
    chartType: 'clusteredBar',
    isDataTransposed: true,
    seriesData: [['', 'Q1', 'Q2'], ['Revenue', 100, 112]],
  };

  createApp({
    render: () => h(InsightChart, { chartData, style: 'height: 400px' }),
  }).mount('#app');
</script>

The import map must map both vue and @chartbuddy.io/embed/vue, and the subpath needs the explicit .mjs file — bare-specifier subpath resolution does not work in browsers.

For a standalone artifact with no framework at all, the custom element needs no import map.

Why use the wrapper

new Insight() owns a DOM node and lives across renders. The wrapper handles the lifecycle so you don't:

  • Data changes patch instead of remount. A new chartData calls update() on the live instance. Rebuilding the chart on every change makes an embedded editor feel broken.
  • Only construction options remount. Changing editable or instanceId rebuilds the chart; everything else is applied in place.
  • Reactive proxies never reach the engine. The wrapper passes toRaw() config, so Vue's proxy wrapper doesn't leak into chart internals.
  • Unmount destroys. Listeners and the instance are cleaned up on onBeforeUnmount.

Editable charts with two-way data

vue
<script setup>
import { ref } from 'vue';
import { InsightChart } from '@chartbuddy.io/embed/vue';

const chartData = ref(initialConfig);

function onChange(cd) {
  chartData.value = cd;
}
</script>

<template>
  <InsightChart
    :chart-data="chartData"
    editable
    style="height: 480px"
    @change="onChange"
  />
  <button @click="save(chartData)">Save</button>
</template>

change fires after live edits in edit mode, after programmatic updates, and on Done. Feeding it straight back into chartData is safe — the wrapper compares by identity and the object it hands you is the one it already applied.

Assign, don't mutate

chartData is compared by identity, not deeply. Mutating a nested property in place will not be detected:

js
// Not picked up — same object identity
chartData.value.title.text = 'FY26';

// Picked up
chartData.value = { ...chartData.value, title: { text: 'FY26' } };

Events

EventPayload
readyThe Insight instance
changeChartData | null
mode'view' | 'edit'
errorError — a ChartDataValidationError for invalid config

useInsight for imperative access

When you need the instance itself — PNG export, edit mode, revision tracking — use the composable and place the container yourself.

vue
<script setup>
import { ref } from 'vue';
import { useInsight } from '@chartbuddy.io/embed/vue';

const chartData = ref(config);

const { containerRef, insight, ready, error } = useInsight({
  chartData,
  instanceId: 'revenue',
  onReady: () => console.log('booted'),
});
</script>

<template>
  <div ref="containerRef" style="height: 400px" />
  <button :disabled="!ready" @click="insight.downloadPng()">Download PNG</button>
  <button :disabled="!ready" @click="insight.enterEditMode()">Edit</button>
  <p v-if="error" role="alert">{{ error.message }}</p>
</template>

chartData accepts a plain object, a ref, or a getter. insight is a shallowRef holding null until the mount resolves — guard imperative calls on ready.

What remounts, what patches

Prop changeEffect
chartDataupdate() on the live instance
instanceId, editable, toolbar, persist, assetBase, hostOverridesFull remount (destroy + construct)
Anything else in the parentNothing

Toggling editable remounting is deliberate: view mode and the full editor are different mounts. If you toggle it often, prefer one mount plus insight.enterEditMode() / exitEditMode().

Handling invalid data

Chart data is validated at the API boundary, so bad data fails at mount. The wrapper surfaces it rather than throwing through your render:

vue
<script setup>
import { ChartDataValidationError } from '@chartbuddy.io/embed';

function onError(err) {
  if (err instanceof ChartDataValidationError) {
    issues.value = err.errors; // [{ path, code, expected, suggestion }, …]
  }
}
</script>

<template>
  <InsightChart :chart-data="fromLLM" @error="onError" />
</template>

See Validation.

Dashboards

One <InsightChart> per chart, each with a stable instance-id. Duplicate ids on a page throw, so derive them from your data rather than the loop index if the list can reorder.

vue
<InsightChart
  v-for="panel in panels"
  :key="panel.id"
  :instance-id="panel.id"
  :chart-data="panel.chartData"
  :persist="false"
  style="height: 300px"
/>

The engine loads once per page, not once per chart — but read Installation before putting a lot of charts on one screen.

Nuxt / SSR

The bindings are browser-only: the chart engine needs a real DOM. The mount happens in onMounted, so nothing runs during SSR, but wrap usage in <ClientOnly> so Nuxt does not try to render it on the server:

vue
<ClientOnly>
  <InsightChart :chart-data="chartData" style="height: 400px" />
</ClientOnly>

There is no headless/Node render path today, so charts cannot be pre-rendered to PNG on a server.

Developer & LLM documentation · Not the end-user Help Center · Help Center