Angular components leave custom elements in the dom and that breaks styles which rely on child selectors. Here's a workaround.

Versions used below

{
"@angular/core": "4.0.3"
}

Scenario

You've got some Angular components that look like

/* parent */
import { Component } from '@angular/core';

@Component({
selector: 'my-list',
template: `
<ul>
<my-list-item></my-list-item>
</ul>
`

})
export class ListComponent {}

and

/* child */
import { Component } from '@angular/core';

@Component({
selector: 'my-list-item',
template: `
<li>
<span>1</span>
</li>
`

})
export class ListItemComponent {}

Since Angular components leave their custom elements in the dom, you get this dom nesting

<my-list>
<ul>
<my-list-item>
<li>
<span>1</span>
</li>
</my-list-item>
</ul>
</my-list>

Problem

The nesting seen above breaks styles that use child selectors:

/* selector no longer matches */
ul > li {

}

Workaround

Change the child component's selector to something else, like an attribute selector.

@Component({
// changed to attribute selector
selector: '[my-list-item]',

// or even
// selector: 'li[my-list-item]',

// outer li is removed because it'll be in parent template now
template: `
<span>1</span>
`

})

Parent template changes to

<ul>
<li my-list-item></li>
</ul>

the dom becomes

<my-list>
<ul>
<li my-list-item="">
<span>1</span>
</li>
</ul>
</my-list>

and now the child selector matches. Sweet.

What about binding things on child's root element?

We lost the ability to bind things on the <li> because that moved out of the child template.

@HostBinding() and @HostListener() can let us achieve that.

import { Component, HostBinding, HostListener } from '@angular/core';

@Component({
selector: '[my-list-item]',
template: `
<span>1</span>
`
,
})
export class ListItemComponent {
// Equivalent to <li [class.active]="hasActiveClass">
@HostBinding('class.active') hasActiveClass: boolean = false;

// Equivalent to <li (click)="handleClick()">
@HostListener('click') handleClick() {
this.hasActiveClass = !this.hasActiveClass;
}
}

Well, that wasn't ideal but it worked.