Guide
Marks as Children
Define Observable Plot marks as Vue template components with the Plot prefix, stack multiple marks, and understand the children-over-props rule.
Use <Plot*> components directly in your Vue template. Each mark from Observable Plot maps to a component with Plot prefix and PascalCase naming.
Basic example
App.vue
<script setup lang="ts">
import { VPlot } from '@memotux/vue-plot'
const data = [
{ name: 'A', value: 10 },
{ name: 'B', value: 20 },
{ name: 'C', value: 15 },
]
</script>
<template>
<VPlot :width="680">
<PlotBarY :data="data" x="name" y="value" />
</VPlot>
</template>
Multiple marks
Stack multiple marks in a single plot:
App.vue
<template>
<VPlot :width="680" :height="400">
<PlotBarY :data="data" x="name" y="value" />
<PlotRuleY :data="[0]" stroke="gray" />
<PlotText
:data="data"
x="name"
y="value"
dy="-8"
textAnchor="middle"
/>
</VPlot>
</template>
Mark naming convention
The mapping from Observable Plot functions to Vue components follows a consistent pattern:
| Observable Plot function | Vue Component |
|---|---|
barY() | <PlotBarY> |
dot() | <PlotDot> |
lineX() | <PlotLineX> |
areaY() | <PlotAreaY> |
ruleX() | <PlotRuleX> |
The rule: Plot + capitalize the mark name.
Passing data
Each mark component accepts a data prop plus all options from its corresponding Observable Plot function:
App.vue
<PlotDot
:data="scatterData"
x="weight"
y="height"
r="age"
fill="blue"
tip
/>
The data prop is separate from the mark options — it's not mixed in with channels like x, y, fill.
Combining mark types
Mix different mark types to build complex visualizations:
App.vue
<template>
<VPlot :width="680" :height="400">
<!-- Background frame -->
<PlotFrame stroke="#eee" />
<!-- Data points -->
<PlotDot :data="points" x="x" y="y" fill="steelblue" />
<!-- Trend line -->
<PlotLinearRegressionY
:data="points"
x="x"
y="y"
stroke="red"
strokeWidth="2"
/>
<!-- Reference line -->
<PlotRuleY :data="[0]" stroke="#ccc" />
</VPlot>
</template>
Priority rule
If marks are provided both as props and as children, only child marks are rendered:
App.vue
<!-- Only PlotBarY renders — the marks prop is ignored -->
<VPlot :marks="[frame()]">
<PlotBarY :data="data" x="name" y="value" />
</VPlot>
Requirements
Using mark components as children requires the Vite plugin configuration:
vite.config.ts
import { plotCustomElement } from '@memotux/vue-plot'
export default defineConfig({
plugins: [
vue({
template: plotCustomElement.template,
}),
],
})
When using camelCase attributes like
textAnchor or strokeWidth inside a Single-File Component, Vue's compiler maps them correctly. If you instead place these marks directly in a DOM template (e.g. an index.html<div id="app">), the browser lowercases attribute names and the props won't bind. Prefer SFC usage, or use kebab-case equivalents such as text-anchor and stroke-width in DOM templates.What's next?
- Marks as Props — Functional mark definition
- Reactive Data — Update plots dynamically