Repository navigation
Description
Which @angular/* package(s) are relevant/related to the feature request?
compiler, compiler-cli, core
Description
<ng-container>, <ng-template>, and <ng-content> don't render an element. Angular accepts
bindings and attributes on them that can never take effect, and most of them compile and run
without a word:
<ng-container class="card" [class.active]="isActive" (click)="select()">...</ng-container>
<ng-template [title]="label" (click)="missing()">...</ng-template>
<ng-content selector="h1" />Nothing on these lines does anything:
- Class, style, and event bindings on
<ng-container>and<ng-template>are ignored, unless a
directive claims them. - Bindings that no directive claims on
<ng-template>aren't type-checked, so
(click)="missing()"compiles. <ng-content>ignores every binding, and every attribute exceptselectandngProjectAs. The
selectortypo (forselect) silently makes the slot a default slot. Angular's own upgrade
examples have had this typo since 2017.NO_ERRORS_SCHEMAhides unknown properties on<ng-container>, although no schema can give it
a property.- Inside
<svg>,[attr.x]on<ng-container>skips its parse error and throws a misleading
assertion in dev mode.
Proposed solution
Report what Angular ignores, and nothing that takes effect. Code generation and runtime behavior
don't change.
Step 1, not breaking:
- NG8031
ignoredBinding, a new type-check diagnostic. It needs
strictTemplates, is a warning by default, and is configured through
extendedDiagnostics.checks, like NG8011. It reports class, style,attr., animation, and
event bindings that no directive claims, every binding on<ng-content>, and static attributes
that nothing reads. - NG8032, a template type-check warning for a component whose selector matches
<ng-container>or<ng-template>. That compiles today and fails only when the template
renders, in dev and production mode. - The language service stops suggesting DOM attributes on
<ng-container>. - NG0319, a dev-mode runtime log for class, style, and event bindings on
<ng-container>and
<ng-template>, so JIT is covered too. - The
<svg>parse fix.
Step 2, breaking: severities only, in two independent PRs.
- NG8032 is an error.
- NG8031 is an error by default, and NG0319 throws under
errorOnUnknownProperties.
Every new error points at a binding or component that never worked. NG8031 can be set back to
"warning" or "suppress".
Not reported: bindings a directive claims, directive host bindings (directives are reusable),
global event targets, and static attributes that a directive, a structural directive, a content
projection slot, or Angular itself reads.
Question for the team: are the step 2 PRs fine for a minor release, or should they wait for a
major? They can land separately.
PRs: #71882 (step 1); #71883 (NG8032 error) and #71884 (NG8031 error), each building on #71882
Alternatives considered
- A template parse error. The linker re-parses published libraries, so a parse error would
break libraries that compile today. - Only an extended diagnostic. It can warn, but step 2 needs the same check in the type
checker. One check in the type checker serves both levels. - Only a runtime error. It reports late, in dev mode only, and can't see bindings on
<ng-content>or which static attributes something reads. - Also reporting directive host bindings. A directive can apply to elements where those
bindings work, so reporting them would be noise.
Activity
SkyZeroZx commentedon Nov 8, 2026
This reminds me a bit of #69640 for unclaimed bindings on
ng-template, and #70808 / #71844 for class bindings onng-container. In #70808, which mentioned:The
ng-contentpart was also discussed in #24259 and #68715, where it was mentioned:I see this proposal covers more cases, but I think some of these checks could also be handled by ESLint.
So I think maybe we can comment in that issue or PR
Flarette commentedon Nov 8, 2026
I think the proliferation of agents makes the value of compiler diagnostics higher. Also not everybody uses ESLint and oxlint doesn't even support Angular templates.
Fixing compilation for this case is now as easy as a asking agent to "fix it". Every error was silently ignored no-op anyway. This makes it explicit.
Flarette commentedon Nov 8, 2026
Also this one is warning only, it can go into the next release. 2 linked pr's that flip it to error can be shipped with the next major (or minor). I haven't seen the other 2 since it was developed in parallel. This one adds a blanked no-op binding reports for everything while others seems to be a special cases.
JeanMeche commentedon Nov 8, 2026
static classes are valid selectors for content projection, we should probably not regress on this.
Flarette commentedon Nov 8, 2026
Agreed, and that’s kept: NG8031 doesn’t report static attributes, class included, on a node that a specific
<ng-content select>slot selects. Slot matching includes class names, soselect=".card-body"counts. A static class is reported only when no directive matches the node and no specific slot selects it, which is when it has no effect. I’ll add a test for the class case to #71882.JeanMeche commentedon Nov 8, 2026
Fyi, About
ng-templateI was testing things on #71887 and it raised a behavior that was implemented by #53457.Flarette commentedon Nov 8, 2026
Thanks for flagging it. #71882 keeps that behavior. On an explicit
<ng-template>, it treats[attr.x],[class.x], and[style.x]as property bindings namedx, as the compiler has done since #53457 (compilesToProperty). A directive input namedxclaims them, so NG8031 only reports the ones nothing claims.Covered in
ignored_bindings_spec.ts:should not report a class binding on ng-template(p-input-dir [class.p])should not report a style binding on ng-template(p-input-dir [style.p])should not report an attribute binding on ng-template(p-input-dir [attr.p])should report a class binding on ng-templateandshould report an attribute binding on ng-template(no directive claims them)The
ng_template_bindingscompliance test from #53457 stays as it is.Is this the behavior you ran into on #71887, or was it something else?