{"record":{"id":"af27e7fb14912cd9","repo":"hcengineering/platform","slug":"please-use-the-nodeviewwrapper-component-for-your","errorCode":null,"errorMessage":"Please use the NodeViewWrapper component for your node view.","messagePattern":"Please use the NodeViewWrapper component for your node view\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugins/text-editor-resources/src/components/node-view/svelte-node-view-renderer.ts","lineNumber":104,"sourceCode":"    target.classList.add(contentClass)\n\n    this.contentDOMElement = null\n    const context = createNodeViewContext({\n      onDragStart: this.onDragStart.bind(this),\n      onContentElement: (element) => {\n        this.contentDOMElement = element\n      }\n    })\n\n    this.renderer = new SvelteRenderer(this.component, { element: target, props, context })\n\n    this.editor.on('update', this.handleEditorUpdate.bind(this))\n    this.editor.on('selectionUpdate', this.handleSelectionUpdate.bind(this))\n  }\n\n  override get dom (): HTMLElement {\n    if (this.renderer.element.firstElementChild?.hasAttribute('data-node-view-wrapper') === false) {\n      throw Error('Please use the NodeViewWrapper component for your node view.')\n    }\n\n    return this.renderer.element\n  }\n\n  override get contentDOM (): HTMLElement | null {\n    if (this.node.isLeaf) {\n      return null\n    }\n\n    return this.contentDOMElement\n  }\n\n  override stopEvent (event: Event): boolean {\n    if (typeof this.options.stopEvent === 'function') {\n      return this.options.stopEvent({ event })\n    }\n    return super.stopEvent(event)","sourceCodeStart":86,"sourceCodeEnd":122,"githubUrl":"https://github.com/hcengineering/platform/blob/63e28dc96483967b2fc21c881b3f1023c1de7718/plugins/text-editor-resources/src/components/node-view/svelte-node-view-renderer.ts#L86-L122","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Use the NodeViewWrapper component as the root of your Svelte node view component","Ensure the root element carries the data-node-view-wrapper attribute (NodeViewWrapper adds it)","Keep exactly one root element inside the component template so firstElementChild is the wrapper","After changing the component, rebuild and remount the editor so the renderer re-renders"],"exampleFix":"<!-- before -->\n<div class=\"my-node\">...</div>\n<!-- after -->\n<NodeViewWrapper class=\"my-node\">...</NodeViewWrapper>","handlingStrategy":"validation","validationCode":"// In your Svelte node view component, verify the root wraps content correctly before registering:\nconst root = document.querySelector('.my-node-view')\nif (root === null || !root.hasAttribute('data-node-view-wrapper')) {\n  throw new Error('Node view component must render NodeViewWrapper as its root')\n}","typeGuard":"function hasNodeViewWrapper(el: Element | null | undefined): el is HTMLElement {\n  return el instanceof HTMLElement && el.hasAttribute('data-node-view-wrapper')\n}","tryCatchPattern":"try {\n  const dom = nodeView.dom\n} catch (err) {\n  if (err instanceof Error && err.message.includes('NodeViewWrapper')) {\n    console.error('Custom node view must use NodeViewWrapper as root component', err)\n    return fallbackNodeView\n  }\n  throw err\n}","preventionTips":["Always use NodeViewWrapper (or an element with data-node-view-wrapper) as the single root of your node view component","Follow current library examples when upgrading text-editor packages; wrapper requirements can change","Test each custom node view by opening the editor with that node before shipping","Keep one root element per component template so firstElementChild is the wrapper"],"tags":["svelte","tiptap","prosemirror","node-view","text-editor"],"backgroundTag":"node-view-wrapper-missing","analyzedSha":"63e28dc96483967b2fc21c881b3f1023c1de7718","analyzedAt":"2026-08-29T15:21:27.377Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}