Component Selectors
Every Angular component declares a selector that tells the framework where to instantiate it in a template. The selector is a CSS-like matcher: most often you write a custom HTML element, but Angular also supports attribute and class selectors, which is how built-in directives like routerLink attach to existing elements. Choosing the right selector strategy keeps your markup readable and avoids clashing with native HTML or other libraries.
Element selectors
The default and most common strategy is the element (tag) selector. You name the component as if it were a custom HTML element, and Angular renders the component wherever that tag appears.
import { Component } from '@angular/core';
@Component({
selector: 'app-user-card',
standalone: true,
template: `<p>User card</p>`,
})
export class UserCardComponent {}
You then use it as a tag in another component’s template:
<app-user-card></app-user-card>
Element selectors give you self-contained, easily readable markup. The component owns its own DOM element, so it is the natural choice for “block” UI such as cards, panels, and pages.
Attribute selectors
An attribute selector wraps the name in square brackets. Instead of creating a new element, the component (or directive) attaches to an existing element that carries that attribute. This is ideal when you want to enhance a native element while keeping its semantics and accessibility intact.
import { Component } from '@angular/core';
@Component({
selector: 'button[appPrimary]',
standalone: true,
template: `<ng-content />`,
host: {
class: 'btn btn-primary',
},
})
export class PrimaryButtonComponent {}
<button appPrimary>Save changes</button>
Here the rendered DOM is still a real <button>, so keyboard handling, form submission, and screen-reader behavior all work without extra effort. The selector: 'button[appPrimary]' form also constrains the component to <button> elements only — applying appPrimary to a <div> would not match.
Prefer attribute selectors when the underlying element type matters for accessibility or forms. Wrapping a native
<button>is almost always better than rebuilding one from a<div>.
Class selectors
A class selector matches elements by CSS class using a leading dot. It is the least common strategy and is generally reserved for migrating older CSS-driven widgets, since it blurs the line between styling hooks and behavior.
import { Component } from '@angular/core';
@Component({
selector: '.app-tooltip-host',
standalone: true,
template: `<ng-content />`,
})
export class TooltipHostComponent {}
<span class="app-tooltip-host">Hover me</span>
Because a class is also a styling concern, it is easy to attach behavior accidentally. Use this strategy sparingly and document it clearly.
Comparing selector strategies
| Strategy | Syntax | Renders | Best for |
|---|---|---|---|
| Element | 'app-thing' | A new custom element | Self-contained UI blocks |
| Attribute | '[appThing]' or 'button[appThing]' | Attaches to existing element | Enhancing native/host elements |
| Class | '.app-thing' | Attaches via CSS class | Legacy/CSS-driven migrations |
You can also combine matchers. The selector 'input[appAutofocus]:not([readonly])' matches autofocus inputs that are not read-only, and a comma creates an OR group: 'app-icon, [appIcon]'.
Naming conventions
Angular’s style guide recommends prefixing every custom element selector with a short, hyphenated, lowercase namespace — app- by default, or a feature/library prefix such as admin- or mat-. This prevents collisions with current and future native HTML elements (which never contain a hyphen but may gain new names over time) and clearly signals which components belong to your team.
- Element selectors:
kebab-casewith a prefix, e.g.app-user-card. - Attribute and class selectors:
camelCaseto match directive naming, e.g.appPrimary.
You configure the project-wide prefix in angular.json, and the Angular CLI lints against it:
{
"projects": {
"my-app": {
"prefix": "app"
}
}
}
Output:
src/app/user/user-card.component.ts:4:13 - error NG-LINT:
The selector of the component "UserCardComponent" should have prefix "app"
(https://angular.dev/style-guide#component-selector)
Avoid bare, prefix-less element selectors like
cardorbutton. They can shadow real or upcoming native elements and make components hard to trace back to their source.
Best practices
- Use a consistent, hyphenated prefix (
app-, or a library prefix) on every element selector to avoid collisions and improve traceability. - Reach for attribute selectors when enhancing native elements so you keep built-in accessibility and form behavior.
- Constrain attribute selectors to a specific tag (e.g.
button[appPrimary]) when the host element type is required for correctness. - Use
kebab-casefor element selectors andcamelCasefor attribute/class selectors to match directive conventions. - Avoid class selectors except when migrating legacy CSS widgets — they conflate styling hooks with behavior.
- Keep selectors short and descriptive; the selector is part of your component’s public API and renaming it later is a breaking change for consumers.