React integration
Mount the editor and portals through the React adapter while preserving application context.
Minimal integration
MsfeEditorContent handles mounting and cleanup, and onReady exposes the current instance. Options provide initial configuration; use instance methods to update an editor that is already mounted.
import { MsfeEditorContent } from '@quirekit/msfe-react'
import { StarterKit } from '@quirekit/msfe-starter-kit'
import type { ReactEditorOptions } from '@quirekit/msfe-react'
const options: ReactEditorOptions = {
markdown: '# Hello, Markdown',
mode: 'live',
extensions: [StarterKit],
}
/** @returns The editor component in the current application. */
export function EditorExample() {
return <MsfeEditorContent options={options} />
}
Custom host layout
To place the mount element yourself, use useMsfeEditor(parentRef, optionsFactory). It returns the current session or null; the session contains editor and host. Keep ReactNodeViewHost within your existing provider tree.
import { useRef } from 'react'
import { useMsfeEditor, ReactNodeViewHost } from '@quirekit/msfe-react'
import { StarterKit } from '@quirekit/msfe-starter-kit'
/** @returns An editor and component-view host that retain context. */
export function EditorWithHost() {
const parent = useRef<HTMLDivElement>(null)
const session = useMsfeEditor(parent, () => ({
markdown: 'Start editing.',
extensions: [StarterKit],
}))
return <>
<div ref={parent} />
{session && <ReactNodeViewHost host={session.host} />}
</>
}
Context and StrictMode
ReactNodeViewRenderer() and ReactComponentViewRenderer() use portals within the same host. Development StrictMode repeats the effect lifecycle, so onReady may run again; do not treat it as a business action that runs exactly once.
QuireKit's public component library currently provides Vue components. The React adapter supports your application's React UI while keeping the field and transaction contracts consistent.
React NodeView shape
The component receives nodeView and reuses the framework-independent codec. Use the Portal Host to preserve Context instead of creating a separate React root per node.
import type { MsfeNodeViewProps } from '@quirekit/msfe-core'
import { MsfeEditorContent, ReactNodeViewRenderer } from '@quirekit/msfe-react'
import { StarterKit } from '@quirekit/msfe-starter-kit'
import { Status } from './status'
interface StatusAttributes { readonly value: 'todo' | 'done' }
function StatusView({ nodeView }: { nodeView: MsfeNodeViewProps<StatusAttributes> }) {
return <button disabled={nodeView.readOnly} onClick={() => nodeView.updateAttributes({
value: nodeView.attrs.value === 'done' ? 'todo' : 'done',
})}>{nodeView.attrs.value}</button>
}
// Status is the framework-independent extension from the custom-node tutorial.
const StatusWithUI = Status.extend({
addNodeView() { return ReactNodeViewRenderer(StatusView) },
})
/** @returns A mounted editor using the custom React node view. */
export function StatusEditor() {
return <MsfeEditorContent options={{
markdown: '# Status\n\n[[todo]]', mode: 'live',
extensions: [StarterKit, StatusWithUI],
}} />
}
Copy the framework-independent status.ts and types.ts from the node tutorial beside this component first. Replace the illustrative native button with your React component library. Generic controls use ReactComponentViewRenderer and receive view, not nodeView.
Updates and cleanup
Saving, modes and external changes use the same instance APIs. Avoid feeding whole-document changes back into options and triggering remounts. Re-establish host subscriptions for each session and clean up effects rather than retaining stale editor references.
React snippets describe the public integration. This site's interactive examples run in Vue; consuming React apps should verify StrictMode, SSR and routing themselves.