The EditorOptions interface (packages/core/src/editor/editor.ts):
export interface EditorOptions<E extends Extension> { /** * The extension to use when creating the editor. */ extension: E /** * The starting document. Can be: * - ProseMirror node JSON object * - HTML string * - DOM Element instance */ defaultContent?: NodeJSON | string | Element /** * A JSON object representing the starting selection. * Only used when defaultContent is also provided. */ defaultSelection?: SelectionJSON}
The defaultContent is processed through defineDefaultState() extension internally, which converts it to a ProseMirror document.
// Mount and get cleanup functionconst unmount = editor.mount(element)// Later, unmountunmount()// Or use the method directlyeditor.unmount()// Re-mount to a different elementeditor.mount(anotherElement)
Mounting an already-mounted editor to a different element throws an error. Unmount first, then mount to the new element.
// Get current stateconst state = editor.state// Access documentconst doc = state.doc// Access selectionconst selection = state.selection// Check if focusedif (editor.focused) { console.log('Editor has focus')}
// Get content as JSONconst json = editor.getDocJSON()// Get content as HTMLconst html = editor.getDocHTML()// Set content from JSONeditor.setContent({ type: 'doc', content: [...] })// Set content from HTMLeditor.setContent('<p>New content</p>', 'start')// Set content from DOM elementconst div = document.createElement('div')div.innerHTML = '<p>Content</p>'editor.setContent(div, 'end')
// Execute a commandconst success = editor.commands.toggleBold()// Check if command can be executedif (editor.commands.toggleBold.canExec()) { editor.commands.toggleBold()}// Execute a ProseMirror command directlyimport { undo } from '@prosekit/pm/history'if (editor.canExec(undo)) { editor.exec(undo)}
When you call editor.use(extension) (packages/core/src/editor/editor.ts:233-254):
Before Mount: Extension is queued for later registration
After Mount: Extension is immediately added to the editor
Facet tree is updated using unionFacetNode()
Plugins are reconfigured if changed
Commands are registered if new
public use(extension: Extension): VoidFunction { if (!this.mounted) { // Queue for after mount let canceled = false let lazyRemove: VoidFunction | null = null const lazyCreate = () => { if (!canceled) { lazyRemove = this.use(extension) } } this.afterMounted.push(lazyCreate) return () => { canceled = true lazyRemove?.() } } // Add extension immediately this.updateExtension(extension, true) return () => this.updateExtension(extension, false)}
Dynamic extensions cannot change the schema. The schema is frozen at editor creation. Attempting to add nodes or marks dynamically will throw a ProseKitError.
// Create a new stateconst newState = EditorState.create({ doc: newDoc, plugins: editor.state.plugins,})// Update the editoreditor.updateState(newState)
Direct state updates bypass plugins and may break editor functionality. Only use this for specific advanced use cases.