Angular Component styling – Using shadow piercing descendant selector

In this post, I am going to share how the shadow piercing descendant selector helped me with style scoping problem.

Well, I tried to create Angular wrapper for one of a JQuery plugin. All worked as planned and later I noticed that I was not able to apply custom styles to the plugin in ViewEncapsulation.Emulated mode. I can set the custom style when the ViewEncapsulation is set to None.

So I started to search for a solution to apply the custom style in ViewEncapsulation.Emulated mode.

What does ViewEncapsulation emulated mode actually do?

In ViewEncapsulation.Emulated mode, angular will try to emulate the style scoping feature of Shadow DOM. This is achieved by adding attribute to the element and style.

@Component({
    selector: 'my-app',
    template: `
<div>
<h2>Hello {{name}}</h2>
</div>
`,
    styles: [`h2 {
       color: red
    }`]
})
export class App {
   name:string;
   constructor() {
     this.name = `Angular! v${VERSION.full}`
   }
}

Extra attribute will be added to the template elements as follows.

b1

b2

Why component style is not applied to the JQuery plugin?

Inside the plugin the element creation is done by JQuery instead of Angular. So the attributes used to emulate style scoping is not added to the elements.

To illustrate this, check the below code example in which the dynamic h2 element is appended in the ngAfterViewInit lifecycle.


@Component({
    selector: 'my-app',
    template: `
<div>
<h2>Hello {{name}}</h2>
</div>
`,
    styles: [`::ng-deep h2 {
      color: red
    }`]
})
export class App {
     name:string; ele;
     constructor(eleRef: ElementRef) {
       this.name = `Angular! v${VERSION.full}`
       this.ele = eleRef;
     }
     ngAfterViewInit() {
       let dynam = document.createElement('h2');
       dynam.innerHTML = 'Dynamic content ' + this.name;
       this.ele.nativeElement.appendChild(dynam);
     }
}

The result will be as follow, you can see that the style from the component is not applied to the dynamically inserted h2 element.

out
Dynamic element insertion – style is not applied

Shadow piercing descendant selector to the rescue

To resolve the above depicted problem, you can use the shadow piercing descendant selector. It is a technique introduced in shadow DOM concept which is deprecated in major browsers.

But you can use this in Angular using the ::ng-deep special selector. This selector will apply the parent component styles to the descendant child components.

The encapsulation mode should be Emulated to use this feature in Angular

Now the component style should be modified as follows


::ng-deep h2 {
   color: red
}

The result will be as follows

oute
Dynamic element insertion – with ::ng-deep selector

Samplehttps://plnkr.co/edit/qb9m0qglyDNzmizQkC9d?p=preview

Reference

  1. https://angular.io/guide/component-styles#deprecated-deep–and-ng-deep
  2. https://angular.io/guide/component-styles#view-encapsulation
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s