229
votes

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.

8

8 Answers

366
votes

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;
}
222
votes

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>
29
votes

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() {}
}
11
votes

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

3
votes

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".

2
votes

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

host: {class: 'A B C'}

1
votes

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>
-1
votes

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!