{"record":{"id":"ee80848bc6dc3498","repo":"angular/components","slug":"dom-portal-content-must-be-attached-to-a-parent-no","errorCode":null,"errorMessage":"DOM portal content must be attached to a parent node.","messagePattern":"DOM portal content must be attached to a parent node\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/cdk/portal/dom-portal-outlet.ts","lineNumber":145,"sourceCode":"      }\n    });\n\n    this._attachedPortal = portal;\n\n    // TODO(jelbourn): Return locals from view.\n    return viewRef;\n  }\n\n  /**\n   * Attaches a DOM portal by transferring its content into the outlet.\n   * @param portal Portal to be attached.\n   * @deprecated To be turned into a method.\n   * @breaking-change 10.0.0\n   */\n  override attachDomPortal = (portal: DomPortal) => {\n    const element = portal.element;\n    if (!element.parentNode && (typeof ngDevMode === 'undefined' || ngDevMode)) {\n      throw Error('DOM portal content must be attached to a parent node.');\n    }\n\n    // Anchor used to save the element's previous position so\n    // that we can restore it when the portal is detached.\n    const anchorNode = this.outletElement.ownerDocument.createComment('dom-portal');\n\n    element.parentNode!.insertBefore(anchorNode, element);\n    this.outletElement.appendChild(element);\n    this._attachedPortal = portal;\n\n    super.setDisposeFn(() => {\n      // We can't use `replaceWith` here because IE doesn't support it.\n      if (anchorNode.parentNode) {\n        anchorNode.parentNode.replaceChild(element, anchorNode);\n      }\n    });\n  };\n","sourceCodeStart":127,"sourceCodeEnd":163,"githubUrl":"https://github.com/angular/components/blob/0411926e7d8ae06b32236ec1048a888cfad5abf2/src/cdk/portal/dom-portal-outlet.ts#L127-L163","documentation":"When attaching a DomPortal, the portal's element must currently be in the DOM (have a parentNode), because the outlet records its position with an anchor comment so it can be restored on detach. Attaching a detached element would make restore impossible, so dev-mode throws.","triggerScenarios":"Creating an element via `document.createElement(...)` (or getElementById returning an off-DOM node), wrapping it in `new DomPortal(el)`, then calling `attach`/`attachDomPortal` on a DomPortalOutlet.","commonSituations":"Building detached template elements in code and passing them to DomPortalOutlet; grabbing content via innerHTML parsing (which yields detached nodes); moving/removing the element from the DOM before attaching; tests creating fixtures without inserting them.","solutions":["Insert the element into the document (even temporarily, e.g. `document.body.appendChild(el)`) before creating/attaching the DomPortal","If content is generated, append it to a hidden container in the DOM first","Use a TemplatePortal or ComponentPortal instead of a DomPortal for programmatically-created content","Verify the element is still attached at attach time (`el.isConnected`)"],"exampleFix":"// before\nconst el = document.createElement('div');\noutlet.attach(new DomPortal(el)); // throws: el has no parentNode\n// after\nconst el = document.createElement('div');\ndocument.body.appendChild(el); // or a dedicated hidden container\noutlet.attach(new DomPortal(el));","handlingStrategy":"validation","validationCode":"function canAttachDom(el: HTMLElement): boolean {\n  return el.parentNode != null; // or el.isConnected\n}\nif (canAttachDom(el)) { outlet.attach(new DomPortal(el)); }","typeGuard":"function isInDocument(el: Node): el is Node & {parentNode: Node} {\n  return el.parentNode != null && el.isConnected;\n}","tryCatchPattern":"try {\n  outlet.attach(new DomPortal(el));\n} catch (e) {\n  if (e.message.includes('must be attached to a parent node')) {\n    document.body.appendChild(el);\n    outlet.attach(new DomPortal(el));\n  } else { throw e; }\n}","preventionTips":["Check el.isConnected before creating a DomPortal","Never wrap elements created but not inserted into the document","Prefer TemplatePortal for programmatically generated content","Keep a dedicated hidden container in the DOM for portal source elements"],"tags":["angular","cdk","portal","dom"],"backgroundTag":"detached-dom-portal","analyzedSha":"0411926e7d8ae06b32236ec1048a888cfad5abf2","analyzedAt":"2026-08-31T11:58:23.400Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}