How to add "class" to host element?

AngularAngular2 Template

Angular Problem Overview


I dont't know how to add to my component <component></component> a dynamic class attribute but inside the template html (component.html).

The only solution I found is to modify the item via "ElementRef" native element. That solution seems a little complicated to do something that should be very simple.

Another problem is that CSS has to be defined outside component scope, breaking component encapsulation.

Is there a simpler solution? Something like <root [class]="..."> .... </ root> inside the template.

Angular Solutions


Solution 1 - Angular

This way you don't need to add the CSS outside of the component:

@Component({
   selector: 'body',
   template: 'app-element',
   // prefer decorators (see below)
   // host:     {'[class.someClass]':'someField'}
})
export class App implements OnInit {
  constructor(private cdRef:ChangeDetectorRef) {}
  
  someField: boolean = false;
  // alternatively also the host parameter in the @Component()` decorator can be used
  @HostBinding('class.someClass') someField: boolean = false;

  ngOnInit() {
    this.someField = true; // set class `someClass` on `<body>`
    //this.cdRef.detectChanges(); 
  }
}

Plunker example

This CSS is defined inside the component and the selector is only applied if the class someClass is set on the host element (from outside):

:host(.someClass) {
  background-color: red;
}

Solution 2 - Angular

Günter's answer is great (question is asking for dynamic class attribute) but I thought I would add just for completeness...

If you're looking for a quick and clean way to add one or more static classes to the host element of your component (i.e., for theme-styling purposes) you can just do:

@Component({
   selector: 'my-component',
   template: 'app-element',
   host: {'class': 'someClass1'}
})
export class App implements OnInit {
...
}

And if you use a class on the entry tag, Angular will merge the classes, i.e.,

<my-component class="someClass2">
  I have both someClass1 & someClass2 applied to me
</my-component>

Solution 3 - Angular

You can simply add @HostBinding('class') class = 'someClass'; inside your @Component class.

Example:

@Component({
   selector: 'body',
   template: 'app-element'       
})
export class App implements OnInit {

  @HostBinding('class') class = 'someClass';

  constructor() {}      

  ngOnInit() {}
}

Solution 4 - Angular

If you want to add a dynamic class to your host element, you may combine your HostBinding with a getter as

@HostBinding('class') get class() {
    return aComponentVariable
}

Stackblitz demo at https://stackblitz.com/edit/angular-dynamic-hostbinding

Solution 5 - Angular

> Another problem is that CSS has to be defined outside component scope, breaking component encapsulation

This is not true. With scss (SASS) you can easily style the component (itself;host) as so:

:host {
    display: block;
    position: absolute;
    width: 100%;
    height: 100%;
    pointer-events: none;
    visibility: hidden;

    &.someClass {
        visibility: visible;
    }
}

This way the encapsulation is "unbroken".

Solution 6 - Angular

for multiple classes situation, as @jbojcic mentioned above, you can use:

host: {class: 'A B C'}

Solution 7 - Angular

In addition to @JoshuaDavid answer, there is another way to define static class, which works on angular v8 when I tried (might also work on older versions):

@Component({
selector: "my-component.someClass1.someClass2",
...
})

which will generate following output:

<my-component class="someClass1 someClass2">
 ...
</my-component>

you can also just use this way:

@Component({
selector: ".someClass1.someClass2",
...
})

which will generate following output:

<div class="someClass1 someClass2">
 ...
</div>

Solution 8 - Angular

this is what I did:

import { Component, Attribute, HostBinding } from "@angular/core";

@Component({
    selector: "selector-el",
    template: ...                                            
})
export class MyComponent {
    @HostBinding('class') get classAttribute(): string {
        let defaultClasses = 'selector-el-class';
        return defaultClasses + ' ' + this.classNames;
    }

    constructor(
        @Attribute('class') public classNames: string
    ) { }
}

Solution 9 - Angular

Here's how I did it (Angular 7):

In the component, add an input:

@Input() componentClass: string = '';

Then in the component's HTML template add something like:

<div [ngClass]="componentClass">...</div>

And finally in the HTML template where you instance the component:

<root componentClass="someclass someotherclass">...</root>

Disclaimer: I'm fairly new to Angular, so I might be just getting lucky here!

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionlascarayfView Question on Stackoverflow
Solution 1 - AngularGünter ZöchbauerView Answer on Stackoverflow
Solution 2 - AngularJoshuaDavidView Answer on Stackoverflow
Solution 3 - AngularMike D3ViD TysonView Answer on Stackoverflow
Solution 4 - AngularSakshamView Answer on Stackoverflow
Solution 5 - AngularBernoulli ITView Answer on Stackoverflow
Solution 6 - AngularJoseph WuView Answer on Stackoverflow
Solution 7 - AngularNuryagdy MustapayevView Answer on Stackoverflow
Solution 8 - AngularChris EslerView Answer on Stackoverflow
Solution 9 - AngularzippycoderView Answer on Stackoverflow