@generative-dom/vue
v0.1.0
Published
Official Vue 3 wrapper for Generative DOM streaming markdown renderer
Maintainers
Readme
@generative-dom/vue
Official Vue 3 wrapper for the Generative DOM streaming markdown renderer.
A thin (~150 LOC) layer over @generative-dom/core that handles the Vue lifecycle for you. Two public APIs:
<GenerativeDomRenderer>— declarative component for the common "render this markdown string" case.useGenerativeDom()— imperative composable for streaming sources (LLM SDKs, server-sent events, etc.).
Vue is a peer dependency. The wrapper supports Vue 3.3+.
Installation
pnpm add @generative-dom/vue @generative-dom/core
# plus whatever plugins you want, e.g.:
pnpm add @generative-dom/plugin-markdown-base @generative-dom/plugin-markdown-headingComponent usage
<script setup lang="ts">
import { GenerativeDomRenderer } from '@generative-dom/vue';
import { markdownBase } from '@generative-dom/plugin-markdown-base';
import { markdownHeading } from '@generative-dom/plugin-markdown-heading';
const plugins = [markdownBase(), markdownHeading()];
defineProps<{ text: string }>();
</script>
<template>
<GenerativeDomRenderer
:markdown="text"
:plugins="plugins"
class="prose"
/>
</template>When markdown changes the component calls reset() then push() then flush() on the underlying instance, so the container always reflects the latest string. When plugins or debounceMs changes the Generative DOM instance is destroyed and re-created. On unmount destroy() is called.
Props
| Prop | Type | Notes |
| ---- | ---- | ----- |
| plugins | GenerativeDomPlugin[] | Required. |
| markdown | string | Optional. Triggers reset + push + flush when it changes. |
| debounceMs | number | Default 16 (~1 frame). |
| onError | (error) => void | Forwarded to Generative DOM's onError. |
Standard class / style attrs pass through to the container <div>.
Events
| Event | Payload | Notes |
| ----- | ------- | ----- |
| event | (name: string, data: unknown) | Receives plugin events (button-click, link-click, heading-rendered, token, events:progress, interactive:state). |
<GenerativeDomRenderer :markdown="text" :plugins="plugins" @event="onEvent" />Composable usage (streaming)
<script setup lang="ts">
import { onMounted } from 'vue';
import { useGenerativeDom } from '@generative-dom/vue';
import { markdownBase } from '@generative-dom/plugin-markdown-base';
import { markdownHeading } from '@generative-dom/plugin-markdown-heading';
const props = defineProps<{ stream: AsyncIterable<string> }>();
const { containerRef, push, flush, reset } = useGenerativeDom({
plugins: [markdownBase(), markdownHeading()],
});
onMounted(async () => {
reset();
for await (const chunk of props.stream) push(chunk);
flush();
});
</script>
<template>
<div ref="containerRef" class="prose" />
</template>The composable returns:
{
containerRef: Ref<HTMLElement | null>; // attach to your container element
push: (chunk: string) => void;
flush: () => void;
reset: () => void;
on: (event: string, handler) => void;
off: (event: string, handler) => void;
}Why a wrapper?
@generative-dom/core is framework-agnostic and does not depend on Vue. The wrapper exists so Vue users don't have to write the onMounted / onBeforeUnmount / watch plumbing themselves — it is the same code you would write, just maintained centrally.
License
MIT
