angular/components · error · Error
${name} must be attached to an element node. Currently attac
Error message
${name} must be attached to an element node. Currently attached to "${node.nodeName}". What it means
CdkDrag and CdkDropList must be applied to an HTMLElement. assertElementNode validates the host node of the directive and throws when the directive lands on a non-element node (nodeType !== 1), such as a text node or comment node. This typically happens through structural-DOM surprises rather than direct misuse.
Source
Thrown at src/cdk/drag-drop/directives/assertions.ts:16
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.dev/license
*/
/**
* Asserts that a particular node is an element.
* @param node Node to be checked.
* @param name Name to attach to the error message.
*/
export function assertElementNode(node: Node, name: string): asserts node is HTMLElement {
if (node.nodeType !== 1) {
throw Error(
`${name} must be attached to an element node. ` + `Currently attached to "${node.nodeName}".`,
);
}
}
View on GitHub (pinned to 0411926e7d)
Solutions
- Move cdkDrag/cdkDropList onto a real element like a <div>, <li>, or <tr>.
- Replace <ng-container cdkDrag> with a concrete element that carries the directive.
- If the root can change at runtime, ensure the node bound via cdkDragRootElement / cdkDropListRootElement matches a single HTMLElement, not text/comment nodes.
- Inspect the DOM in devtools: the element with the directive must appear as a tag, not a `<!-- -->` comment.
Example fix
// before <ng-container cdkDrag *ngIf="item">...</ng-container> // after <div cdkDrag *ngIf="item">...</div>
Defensive patterns
Strategy: type-guard
Validate before calling
const el = document.querySelector('[cdkDrag]');
if (el && el.nodeType !== 1) {
throw new Error('cdkDrag host must be an element node');
} Type guard
function isElementNode(node: Node): node is HTMLElement {
return node.nodeType === 1;
} Try / catch
try {
dragRef.setRootElement(someNode);
} catch (e) {
if ((e as Error).message.includes('must be attached to an element node')) {
console.warn('Provide a real HTMLElement host for cdkDrag');
} else { throw e; }
} Prevention
- Never put cdkDrag/cdkDropList on <ng-container>.
- Verify the directive host renders as a tag in devtools, not a comment node.
- Use cdkDragRootElement with a selector that matches a real element.
- Test drag setups with structural directives (*ngIf, *ngFor) on wrapper elements.
When it happens
Trigger: cdkDrag or cdkDropList placed on an element that Angular renders as a comment node (e.g. an <ng-container> host), or attached to something whose root becomes a text node; _updateRootElement re-runs the assertion when the root element changes and the new node is not an element.
Common situations: Putting cdkDrag on <ng-container *ngIf=...>; template conditions leaving only a comment placeholder; wrapping cdkDrag in a structural directive that swaps the host node.
Related errors
- CdkDropList could not find an element container matching the
- Invalid DOM structure for drop list. Alternate container ele
- Invalid DOM structure for drop list. All items must be place
- ListKeyManager constructed with a signal must receive an inj
- KeyManager items in typeahead mode must implement the `getLa
AI-assisted analysis of angular/components@0411926e7d (2026-08-31).
Data as JSON: /api/errors/fd032fee858c51e3.
Report an issue: GitHub.