angular/components · error · Error
DOM portal content must be attached to a parent node.
Error message
DOM portal content must be attached to a parent node.
What it means
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.
Source
Thrown at src/cdk/portal/dom-portal-outlet.ts:145
}
});
this._attachedPortal = portal;
// TODO(jelbourn): Return locals from view.
return viewRef;
}
/**
* Attaches a DOM portal by transferring its content into the outlet.
* @param portal Portal to be attached.
* @deprecated To be turned into a method.
* @breaking-change 10.0.0
*/
override attachDomPortal = (portal: DomPortal) => {
const element = portal.element;
if (!element.parentNode && (typeof ngDevMode === 'undefined' || ngDevMode)) {
throw Error('DOM portal content must be attached to a parent node.');
}
// Anchor used to save the element's previous position so
// that we can restore it when the portal is detached.
const anchorNode = this.outletElement.ownerDocument.createComment('dom-portal');
element.parentNode!.insertBefore(anchorNode, element);
this.outletElement.appendChild(element);
this._attachedPortal = portal;
super.setDisposeFn(() => {
// We can't use `replaceWith` here because IE doesn't support it.
if (anchorNode.parentNode) {
anchorNode.parentNode.replaceChild(element, anchorNode);
}
});
};
View on GitHub (pinned to 0411926e7d)
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`)
Example fix
// before
const el = document.createElement('div');
outlet.attach(new DomPortal(el)); // throws: el has no parentNode
// after
const el = document.createElement('div');
document.body.appendChild(el); // or a dedicated hidden container
outlet.attach(new DomPortal(el)); Defensive patterns
Strategy: validation
Validate before calling
function canAttachDom(el: HTMLElement): boolean {
return el.parentNode != null; // or el.isConnected
}
if (canAttachDom(el)) { outlet.attach(new DomPortal(el)); } Type guard
function isInDocument(el: Node): el is Node & {parentNode: Node} {
return el.parentNode != null && el.isConnected;
} Try / catch
try {
outlet.attach(new DomPortal(el));
} catch (e) {
if (e.message.includes('must be attached to a parent node')) {
document.body.appendChild(el);
outlet.attach(new DomPortal(el));
} else { throw e; }
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- DOM portal content must be attached to a parent node.
- Cannot attach component portal to outlet without an Applicat
- Must provide a portal to attach
- Host already has a portal attached
- This PortalOutlet has already been disposed
AI-assisted analysis of angular/components@0411926e7d (2026-08-31).
Data as JSON: /api/errors/ee80848bc6dc3498.
Report an issue: GitHub.