Guide
Marks as Props
Pass Observable Plot mark functions as props to build charts programmatically, with dynamic mark selection and no Vite plugin required.
Pass marks from @observablehq/plot through the marks prop. This functional pattern does not require the Vite plugin configuration.
Basic example
App.vue
<script setup lang="ts">
import { VPlot } from '@memotux/vue-plot'
import { barY } from '@observablehq/plot'
const data = [
{ name: 'A', value: 10 },
{ name: 'B', value: 20 },
{ name: 'C', value: 15 },
]
const options = {
width: 680,
marks: [barY(data, { x: 'name', y: 'value' })],
}
</script>
<template>
<VPlot v-bind="options" />
</template>
When to use this pattern
Choose marks-as-props when:
- Building charts programmatically from configuration objects
- Sharing chart configurations as JSON or computed data
- You want to skip the Vite custom element configuration
- Working with dynamic mark selection based on user input
Multiple marks
Combine multiple mark functions in the marks array:
App.vue
<script setup lang="ts">
import { VPlot } from '@memotux/vue-plot'
import { barY, ruleY, text } from '@observablehq/plot'
const data = [
{ name: 'A', value: 10 },
{ name: 'B', value: 20 },
{ name: 'C', value: 15 },
]
const options = {
width: 680,
height: 400,
marks: [
barY(data, { x: 'name', y: 'value' }),
ruleY([0], { stroke: 'gray' }),
text(data, { x: 'name', y: 'value', dy: -8, textAnchor: 'middle' }),
],
}
</script>
<template>
<VPlot v-bind="options" />
</template>
Programmatic chart building
This pattern works well when building charts from configuration:
App.vue
<script setup lang="ts">
import { computed } from 'vue'
import { VPlot } from '@memotux/vue-plot'
import * as Plot from '@observablehq/plot'
const props = defineProps({
chartType: String,
data: Array,
})
const chartConfig = computed(() => {
const markFn = {
bar: Plot.barY,
dot: Plot.dot,
line: Plot.lineY,
area: Plot.areaY,
}[props.chartType] ?? Plot.barY
return {
width: 680,
marks: [markFn(props.data, { x: 'name', y: 'value' })],
}
})
</script>
<template>
<VPlot v-bind="chartConfig" />
</template>
Using with reactive data
The marks prop is reactive — when you update the marks array, the plot re-renders:
App.vue
<script setup lang="ts">
import { ref, computed } from 'vue'
import { VPlot } from '@memotux/vue-plot'
import { barY } from '@observablehq/plot'
const data = ref([
{ name: 'A', value: 10 },
{ name: 'B', value: 20 },
])
const marks = computed(() => [
barY(data.value, { x: 'name', y: 'value' }),
])
function addEntry() {
data.value = [...data.value, { name: 'D', value: 15 }]
}
</script>
<template>
<VPlot :width="680" :marks="marks" />
<button @click="addEntry">Add Entry</button>
</template>
When using reactive data with the
marks prop, wrap the marks in a computed so they update when data changes. See Reactive Data for full patterns.Comparison with children pattern
| Aspect | Marks as Props | Marks as Children |
|---|---|---|
| Vite config required | No | Yes |
| Vue-native syntax | No | Yes |
| Programmatic building | Natural | Requires h() |
| TypeScript inference | Mark functions typed | Component props typed |
| Dynamic mark selection | Easy | Requires v-if/v-for |
What's next?
- Reactive Data — Update plots dynamically
- Nuxt Integration — Nuxt module setup
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.
Reactive Data
Bind reactive Vue refs and computed properties to Vue Plot marks so charts update automatically when data changes, filters, or swaps datasets.