Vue integration
Mount the editor within your existing component tree, preserving themes, injection, and view lifecycles.
Create and mount
useMsfeEditor() returns the shallow editor ref and component host. Render VueNodeViewHost in your template so component views retain your application's provide/inject context.
<script setup lang="ts">
import { shallowRef } from 'vue'
import { useMsfeEditor, VueNodeViewHost } from '@quirekit/msfe-vue'
import { StarterKit } from '@quirekit/msfe-starter-kit'
const parent = shallowRef<HTMLElement | null>(null)
const { editor, host } = useMsfeEditor(parent, () => ({
markdown: '## Start writing',
mode: 'live',
extensions: [StarterKit],
}))
</script>
<template>
<div ref="parent" />
<VueNodeViewHost :host="host" />
</template>
The composable creates the instance after mounting and disposes of the editor and component host on unmount. Do not create a separate Vue application for node rendering.
options.onError receives runtime errors and exceptions from createMsfeEditor() during creation.
After failed creation, editor.value remains undefined and the component host is disposed.
Display an error and preserve the source before explicitly remounting with corrected configuration.
Without onError, creation exceptions continue to Vue's error handling. Exceptions from the options
factory itself also remain Vue-owned. The composable never retries or rebuilds a document automatically.
Update content and mode
Initial options are not deeply watched. After mounting, use setMode(), setReadOnly(), applyChanges(), or replaceDocument(). Avoid writing the entire document back after each keystroke through a full-text v-model.
Observe editor state in Vue
Use useMsfeState() inside setup() instead of wiring watch(editor), initial snapshots and cleanup yourself:
import { useMsfeState } from '@quirekit/msfe-vue'
const state = useMsfeState(editor) // Pass directly to MdProse.state
const cursor = useMsfeState(editor, {
select: state => state.selection.main.head,
})
The source accepts an instance, ref or getter such as () => props.editor. The result is a readonly
shallow ref. It is undefined before creation, after failed creation, or when the instance is cleared
or destroyed; use v-if="state" to wait for a snapshot. Scope disposal and instance replacement
automatically unsubscribe, without destroying a borrowed editor.
The composable connects to MSFE's subscribeState() and observes accepted CodeMirror states only.
References update synchronously without cloning state, reparsing, serializing the document or writing
back. Components that do not call this composable gain no subscription. select and optional equal
follow the core contract: selectors must be pure and bounded, run once per accepted update, and notify
Vue only when their result changes. Equality defaults to Object.is. For newly allocated objects,
provide a comparator such as equal: (a, b) => a.from === b.from && a.to === b.to.
The selector is fixed when the composable is created. It depends on the supplied immutable state and
does not track other Vue refs read inside it. Combine reactive inputs such as locale with the returned
value in a separate computed(). Use full snapshots for readers and narrow fields for small controls.
MdProse still decides whether selection-only changes can reuse reading content.
Nuxt and server rendering
The editor requires the browser DOM. In Nuxt, use a client component or ClientOnly around the editor mount; documentation and navigation can still render on the server. Reserve reasonable placeholder height to limit layout shifts during loading.
Custom components
Use VueNodeViewRenderer() to replace a source node's UI, or VueComponentViewRenderer() for controls such as search panels. See Custom nodes for the complete field-update lifecycle.
Providers and NodeViews
Provide locale, permissions and host services through the existing application tree. NodeViews and ComponentViews retain that context through the Host; shared/locale.ts demonstrates localization. Do not persist reactive UI objects or services in Markdown attributes.
Changing the complete extension set requires an explicit lifecycle decision: preserve source and required host state, then recreate. The options factory is an initialization entry, not a deep reactive configuration or hot plugin loader.
Nuxt checks
- Create the DOM editor in client-only components and render explanatory content/placeholders on the server.
- Avoid duplicate Vue and CodeMirror state/view copies; deduplicate linked workspace packages in the bundler.
- Install component dependencies in the consuming app rather than relying on documentation-site aliases.
- Resolve unsaved state before routing away. Unmount cleanup alone cannot guarantee persistence.