Skip to main content

6 min read #angular #components #templates #dx #frontend

Selectorless Angular: import a component, use it as a tag

No more selector strings, no more imports arrays. You import a component class and write <UserCard /> in the template. It reads like JSX, compiles faster, and kills a whole category of 'why isn't my component rendering' bugs.

Angular components have always carried a small tax that you stop noticing because you pay it every single time: the selector. You name a component twice — once as a class, once as a CSS selector string — then you list it in an imports array somewhere else, and then you reference it in the template by the string. Three sources of truth for "this component exists and I want to use it here."

Selectorless components collapse that to one. You import the class and you use it directly in the template, by its class name, like a tag:

import { UserCard } from './user-card';

@Component({
  template: `
    <UserCard [user]="currentUser()" (select)="open($event)" />
  `,
})
export class Dashboard {
  currentUser = signal(/* ... */);
}

No selector: 'app-user-card' on the component. No imports: [UserCard] on the host. The import statement is the registration. If you've written any React, this is going to feel deeply familiar — and honestly, in the good way.

The bug class this deletes

Every Angular dev has lost ten minutes to this: you write <app-thing> in a template, nothing renders, no error, and eventually you realize you forgot to add Thing to the imports array. The template treated your component as an unknown element and silently rendered nothing.

With selectorless that bug can't exist. The component reference in the template is bound to the imported symbol. If the import isn't there, it's a compile error pointing at the exact line — not a silent no-op you discover in the browser. Moving an entire failure mode from "runtime mystery" to "red squiggle in the editor" is the kind of DX win that doesn't show up in a changelog headline but saves you constantly.

Why it's also faster, not just nicer

The selector system is global by nature: to compile one template, Angular has to know about every selector that might match an element in it. Selectorless makes component usage local — the compiler sees "this template uses exactly these imported symbols" and nothing else. The team has been explicit that this locality is what makes it a performance story, not just an ergonomics one:

  • Faster compilation, because resolving a template no longer means reasoning about a global selector namespace.
  • A smaller runtime, because the machinery that matched selectors at runtime can shrink when components are referenced directly.
  • Better tree-shaking and tooling, because "what does this template depend on?" becomes a plain list of imports a bundler already understands.

Directives get the same treatment

Selectorless isn't only components. Directives — which today are pure selector magic, attributes that attach behavior from who-knows-where — become explicit too. You import the directive and apply it by name, which means you can finally tell, from the template alone, where a behavior is coming from instead of grepping for an attribute selector across the codebase.

The honest caveat — this one's early

Real talk: of the recent Angular features I'm excited about, this is the least baked. It's in active prototyping with an RFC, landing incrementally in the v21+ line. The syntax in this post reflects the current direction and could shift before it's stable, and there are genuine open questions — how it interoperates with the millions of existing selector-based components, what the migration story looks like, how it plays with content projection. I'm not rewriting production apps around it yet.

But the direction is unmistakably right. Angular has spent the last few years deleting ceremony — standalone components killed NgModules, signals killed a lot of RxJS boilerplate, built-in control flow killed *ngIf/*ngFor. Selectorless is the same energy pointed at the last bit of indirection between "I have a component" and "I'm using it."

The boring conclusion

Selectorless components make Angular templates say what they mean: this template uses these components, here are the imports, done. It reads like JSX, it compiles faster, it shrinks the runtime, and it deletes the "forgot to add it to imports" bug entirely. It's the earliest-stage thing on my Angular watch-list, so temper the hype with patience — but it's also the one that'll most change how a template feels to write. Worth following closely.