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

  1. Insert the element into the document (even temporarily, e.g. `document.body.appendChild(el)`) before creating/attaching the DomPortal
  2. If content is generated, append it to a hidden container in the DOM first
  3. Use a TemplatePortal or ComponentPortal instead of a DomPortal for programmatically-created content
  4. 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

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


AI-assisted analysis of angular/components@0411926e7d (2026-08-31). Data as JSON: /api/errors/ee80848bc6dc3498. Report an issue: GitHub.