hcengineering/platform · error

Please use the NodeViewWrapper component for your node view.

Error message

Please use the NodeViewWrapper component for your node view.

What it means

SvelteNodeViewRenderer mounts a Svelte component inside a ProseMirror NodeView and expects its template to render an element marked with data-node-view-wrapper (what the NodeViewWrapper component provides). The dom getter checks for that attribute and throws if the rendered root lacks it, because ProseMirror would otherwise fail to manage the node content correctly.

Source

Thrown at plugins/text-editor-resources/src/components/node-view/svelte-node-view-renderer.ts:104

    target.classList.add(contentClass)

    this.contentDOMElement = null
    const context = createNodeViewContext({
      onDragStart: this.onDragStart.bind(this),
      onContentElement: (element) => {
        this.contentDOMElement = element
      }
    })

    this.renderer = new SvelteRenderer(this.component, { element: target, props, context })

    this.editor.on('update', this.handleEditorUpdate.bind(this))
    this.editor.on('selectionUpdate', this.handleSelectionUpdate.bind(this))
  }

  override get dom (): HTMLElement {
    if (this.renderer.element.firstElementChild?.hasAttribute('data-node-view-wrapper') === false) {
      throw Error('Please use the NodeViewWrapper component for your node view.')
    }

    return this.renderer.element
  }

  override get contentDOM (): HTMLElement | null {
    if (this.node.isLeaf) {
      return null
    }

    return this.contentDOMElement
  }

  override stopEvent (event: Event): boolean {
    if (typeof this.options.stopEvent === 'function') {
      return this.options.stopEvent({ event })
    }
    return super.stopEvent(event)

View on GitHub (pinned to 63e28dc964)

Solutions

  1. Use the NodeViewWrapper component as the root of your Svelte node view component
  2. Ensure the root element carries the data-node-view-wrapper attribute (NodeViewWrapper adds it)
  3. Keep exactly one root element inside the component template so firstElementChild is the wrapper
  4. After changing the component, rebuild and remount the editor so the renderer re-renders

Example fix

<!-- before -->
<div class="my-node">...</div>
<!-- after -->
<NodeViewWrapper class="my-node">...</NodeViewWrapper>
Defensive patterns

Strategy: validation

Validate before calling

// In your Svelte node view component, verify the root wraps content correctly before registering:
const root = document.querySelector('.my-node-view')
if (root === null || !root.hasAttribute('data-node-view-wrapper')) {
  throw new Error('Node view component must render NodeViewWrapper as its root')
}

Type guard

function hasNodeViewWrapper(el: Element | null | undefined): el is HTMLElement {
  return el instanceof HTMLElement && el.hasAttribute('data-node-view-wrapper')
}

Try / catch

try {
  const dom = nodeView.dom
} catch (err) {
  if (err instanceof Error && err.message.includes('NodeViewWrapper')) {
    console.error('Custom node view must use NodeViewWrapper as root component', err)
    return fallbackNodeView
  }
  throw err
}

Prevention

When it happens

Trigger: Implementing a custom Svelte node view whose component uses a plain <div> or other root element instead of the library's NodeViewWrapper component; renaming or removing the wrapper element/attribute in a custom template; accessing nodeView.dom after the renderer mounted a component without the wrapper.

Common situations: Copy-pasting a Tiptap/Svelte node view example that uses vanilla wrappers; upgrading @hcengineering/text-editor-resources where examples changed to require NodeViewWrapper; writing a minimal custom node view and forgetting the wrapper.

Related errors


AI-assisted analysis of hcengineering/platform@63e28dc964 (2026-08-29). Data as JSON: /api/errors/af27e7fb14912cd9. Report an issue: GitHub.