In modern web development, writing semantically correct HTML is important β for accessibility, browser consistency, and maintainability. But if you're using Angular, you may have run into a frustrating problem: Angular component selectors donβt always play nicely with HTML hierarchy.
By default, Angular components are used with custom tags like:
<app-my-component></app-my-component>But what if you're rendering a list of items?
<ul>
<app-my-component></app-my-component>
</ul>Problem: This structure is invalid HTML. According to the HTML spec, a <ul> must only contain <li> elements. Using a custom element like <app-my-component> breaks semantics, accessibility, and can even confuse assistive technologies.
Angular allows you to define components that attach to native HTML elements using an attribute selector.
In your component:
@Component({
selector: 'li[app-my-component]',
templateUrl: './my-component.component.html',
styleUrls: ['./my-component.component.scss']
})
export class MyComponent {
@Input() data: any;
}And in your parent template:
<ul>
<li app-my-component [data]="INPUT_DATA"></li>
</ul>Now:
- β Your DOM is fully valid
- β Your Angular component logic is preserved
- β The list structure is semantic and accessible
This technique is based on Angularβs support for attribute selectors in components.
Itβs commonly used for cases like <button my-button> or <input custom-input>, but works equally well for list items or any other native HTML tags.
If you're building components that need to fit into specific HTML structures β like <ul>/<li>, <table>/<tr>, etc. β donβt force custom component tags where they donβt belong.
Instead, use attribute selectors to get the power of Angular components without breaking HTML semantics.