Como adicionar e remover classes CSS de forma dinâmica no Angular com ngClass
Descubra como a diretiva ngClass simplifica a manipulação de classes CSS de forma intuitiva e eficiente. Neste post, você aprenderá a adicionar e remover classes CSS condicionalmente. Além disso, mostraremos como a ngClass contribui para um código mais limpo e manutenível.

Uma tarefa comum em projetos frontend é a atribuição dinâmica de classes CSS, ou seja, definir a classe CSS de um elemento com base em uma regra de negócio. Através de algumas revisões de código, tenho observado essa tarefa sendo executada frequentemente com o uso de interpolação ({{}}
), por exemplo:
<div
class="produto
{{ esgotado ? 'produto-esgotado' : '' }}
{{ (!esgotado && porcentagemDeDesconto > 0)
? 'produto-com-desconto'
: ''
}}">
...
</div>
Apesar do exemplo acima não estar errado, podemos alcançar o mesmo objetivo usando recursos nativos do Angular, como a diretiva ngClass
. Neste texto falaremos mais sobre o uso do ngClass
na atribuição dinâmica de classes CSS.
Construção do cenário de estudo
Para iniciar, usei o Angular 18.1 para criar um projeto e preparar os exemplos. A seguir deixei o conteúdo de cada arquivo modificado.
No arquivo app.config.ts, configurei a globalização e a sigla da moeda, conforme já apresentado por aqui:
import { registerLocaleData } from '@angular/common';
import localePT from '@angular/common/locales/pt';
import {
ApplicationConfig,
DEFAULT_CURRENCY_CODE,
LOCALE_ID,
provideZoneChangeDetection,
} from '@angular/core';
import { provideRouter } from '@angular/router';
import { routes } from './app.routes';
registerLocaleData(localePT);
export const appConfig: ApplicationConfig = {
providers: [
{ provide: LOCALE_ID, useValue: 'pt-br' },
{ provide: DEFAULT_CURRENCY_CODE, useValue: 'BRL' },
provideZoneChangeDetection({
eventCoalescing: true,
}),
provideRouter(routes),
],
};
app.config.ts
app.component.ts:
import { CommonModule } from '@angular/common';
import { Component, OnInit } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { EMPTY, Observable, of } from 'rxjs';
export type Produto = {
nome: string;
categoria: string;
preco: number;
porcentagemDeDesconto: number;
esgotado: boolean;
};
@Component({
selector: 'app-root',
standalone: true,
imports: [RouterOutlet, CommonModule],
templateUrl: './app.component.html',
styleUrl: './app.component.css',
})
export class AppComponent implements OnInit {
produtos$: Observable<Produto[]> = EMPTY;
ngOnInit(): void {
this.produtos$ = this.carregarProdutos();
}
carregarProdutos() {
return of<Produto[]>([
{
nome: 'Camisa',
categoria: 'Vestuário',
preco: 59.9,
porcentagemDeDesconto: 20,
esgotado: true,
},
{
nome: 'Calça',
categoria: 'Vestuário',
preco: 129.9,
porcentagemDeDesconto: 0,
esgotado: false,
},
{
nome: 'Tênis',
categoria: 'Vestuário',
preco: 189.9,
porcentagemDeDesconto: 40,
esgotado: false,
},
{
nome: 'Jaqueta',
categoria: 'Vestuário',
preco: 249.9,
porcentagemDeDesconto: 0,
esgotado: false,
},
{
nome: 'Boné',
categoria: 'Vestuário',
preco: 39.9,
porcentagemDeDesconto: 60,
esgotado: false,
},
]);
}
obterClassesCSSPorProduto(produto: Produto): string[] {
const classesCSS = ['produto'];
if (produto.esgotado) {
classesCSS.push('produto-esgotado');
} else {
if (produto.porcentagemDeDesconto > 0) {
classesCSS.push('produto-com-desconto');
}
}
return classesCSS;
}
}
app.component.ts
Arquivo app.component.html utilizando a interpolação para atribuir algumas classes CSS:
@if (produtos$ | async; as produtos) {
<div class="container-produtos">
@for (produto of produtos; track produto.nome) {
@let categoria = produto.categoria;
@let esgotado = produto.esgotado;
@let nome = produto.nome;
@let preco = produto.preco;
@let porcentagemDeDesconto =
produto.porcentagemDeDesconto;
@let precoFinal =
preco * (100 - porcentagemDeDesconto) / 100;
<div
class="produto
{{ esgotado ? 'produto-esgotado' : '' }}
{{ (!esgotado && porcentagemDeDesconto > 0)
? 'produto-com-desconto'
: ''
}}">
<img
src="https://placehold.jp/150x150.png"
alt="Imagem do produto">
<p class="produto-categoria">
{{ categoria }}
@if (esgotado) {
<span> - ESGOTADO!</span>
}
</p>
<h2 class="produto-nome">
{{ nome }}
</h2>
<p class="produto-preco">
{{ precoFinal | currency }}
</p>
@if (porcentagemDeDesconto) {
<del>{{ preco | currency }}</del>
<div>
{{ porcentagemDeDesconto / 100 | percent }} OFF
</div>
}
</div>
}
</div>
}
app.component.html
app.component.css:
.container-produtos {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
gap: 8px;
max-width: 720px;
}
.produto {
border: 4px solid #ccc;
text-align: center;
}
.produto * {
margin: 4px auto;
}
.produto-categoria {
font-size: 1em;
font-weight: bold;
color: #888;
font-family: Georgia, 'Times New Roman', Times, serif;
}
.produto-nome {
font-size: 1.6em;
font-weight: bold;
font-family: 'Segoe UI', Tahoma, Verdana, sans-serif;
margin: 0;
}
.produto-preco {
font-size: 2em;
font-weight: bold;
}
.produto-esgotado {
color: #ccc;
background: #eee;
border-style: dotted;
}
.produto-com-desconto {
border-color: #c35e79;
}
app.component.css
A seguir há uma imagem mostrando o projeto em execução:

Atribuindo classes CSS dinamicamente com ngClass
O Angular tem um recurso chamado ngClass
, que é uma diretiva extremamente útil que oferece diversas vantagens na manipulação de classes CSS de forma dinâmica. Ela permite que você aplique, remova ou alterne classes CSS com base em condições.
Adds and removes CSS classes on an HTML element.
The CSS classes are updated as follows, depending on the type of the expression evaluation:string
- the CSS classes listed in the string (space delimited) are added,Array
- the CSS classes declared as Array elements are added,Object
- keys are CSS classes that get added when the expression given in the value evaluates to a truthy value, otherwise they are removed.
fonte: https://angular.dev/api/common/NgClass?tab=description
Na documentação oficial encontramos os seguintes exemplos do ngClass
:
<some-element
[ngClass]="'first second'">
...
</some-element>
<some-element
[ngClass]="['first', 'second']">
...
</some-element>
<some-element
[ngClass]="{'first': true, 'second': true, 'third': false}">
...
</some-element>
<some-element
[ngClass]="stringExp|arrayExp|objExp">
...
</some-element>
<some-element
[ngClass]="{'class1 class2 class3' : true}">
...
</some-element>
A seguir construí alguns exemplos de como utilizar o ngClass
. Em todos os casos, o resultado visual será exatamente o mesmo.
Exemplo 1: adicionando e removendo (toggle) uma classe CSS de forma dinâmica
Para adicionar ou remover uma classe CSS com base em uma condição booleana, podemos usar a sintaxe: [class.minha-classe-css]="variavel"
. Com essa sintaxe, a classe CSS só é adicionada se a condição for verdadeira. Por exemplo, a classe produto-esgotado
será adicionada se a variável esgotado
for true
; caso contrário, a classe será removida.
<div
class="produto"
[class.produto-esgotado]="esgotado"
[class.produto-com-desconto]="!esgotado
&& porcentagemDeDesconto > 0">
...
</div>
trecho do app.component.html
Exemplo 2: adicionando e removendo (toggle) um conjunto de classes CSS de forma dinâmica
Uma opção similar à anterior é passar um objeto "chave-valor", onde a chave é o nome da classe CSS (ou múltiplos nomes separados por espaço) e o valor é um booleano que indica se a classe deve ser adicionada ou não. Veja o exemplo abaixo:
<div
class="produto
[ngClass]="{
'produto-esgotado': esgotado,
'produto-com-desconto': !esgotado
&& porcentagemDeDesconto > 0
}">
...
</div>
trecho do app.component.html
Exemplo 3: adicionando classes CSS através de um array
Outra opção é passar um array com o nome das classes CSS para o ngClass
. No exemplo a seguir, criei uma função para retornar um objeto do tipo string[]
com cada classe CSS:
<div
[ngClass]="obterClassesCSSPorProduto(produto)">
...
</div>
trecho do app.component.html
obterClassesCSSPorProduto(produto: Produto): string[] {
const classesCSS = ['produto'];
if (produto.esgotado) {
classesCSS.push('produto-esgotado');
} else {
if (produto.porcentagemDeDesconto > 0) {
classesCSS.push('produto-com-desconto');
}
}
return classesCSS;
}
trecho do app.component.ts
Testes unitários
Para concluir, criei um teste unitário que demonstra como validar a atribuição dinâmica de classes CSS com o ngClass
:
import { TestBed } from '@angular/core/testing';
import { AppComponent, Produto } from './app.component';
import { of } from 'rxjs';
describe('AppComponent', () => {
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [AppComponent],
}).compileComponents();
});
it('should create the app', () => {
const fixture =
TestBed.createComponent(AppComponent);
const app = fixture.componentInstance;
expect(app).toBeTruthy();
});
it(`deve tratar as classes CSS de acordo com as
propriedades do produto`, () => {
const produtosMock: Produto[] = [
{
nome: 'Camisa',
categoria: 'Vestuário',
preco: 59.9,
porcentagemDeDesconto: 20,
esgotado: true,
},
{
nome: 'Calça',
categoria: 'Vestuário',
preco: 129.9,
porcentagemDeDesconto: 0,
esgotado: false,
},
{
nome: 'Calça',
categoria: 'Vestuário',
preco: 129.9,
porcentagemDeDesconto: 10,
esgotado: false,
},
];
const fixture =
TestBed.createComponent(AppComponent);
const app = fixture.componentInstance;
spyOn(app, 'carregarProdutos').and.returnValue(
of(produtosMock)
);
fixture.detectChanges();
const compiled =
fixture.nativeElement as HTMLElement;
// ************************************************
// É esperado que seja renderizado um <div
// class="produto"> para cada item da variável
// `produtosMock`:
// ************************************************
expect(
compiled.querySelectorAll('div.produto')
).toHaveSize(produtosMock.length);
// ************************************************
// É esperado que sejam encontramos elementos
// <div> com a classe CSS `produto-esgotado`
// quando produto.esgotado === true
// ************************************************
const qtdProdutosEsgotados = produtosMock.filter(
(a) => a.esgotado
).length;
expect(
compiled.querySelectorAll(
'div.produto.produto-esgotado'
)
).toHaveSize(qtdProdutosEsgotados);
// ************************************************
// É esperado que sejam encontramos elementos
// <div> com a classe CSS `produto-com-desconto`
// quando produto.esgotado === true &&
// produto.porcentagemDeDesconto > 0
// ************************************************
const qtdProdutosEmEstoqueComDesconto =
produtosMock.filter((a) => a.esgotado).length;
expect(
compiled.querySelectorAll(
'div.produto.produto-com-desconto'
)
).toHaveSize(qtdProdutosEmEstoqueComDesconto);
});
});
app.component.spec.ts
Considerações
Existem diversas formas de utilizar o ngClass
no Angular, cada uma com suas vantagens e desvantagens. A escolha da melhor abordagem depende do contexto específico e dos requisitos do seu projeto. Ao decidir como aplicar classes CSS, considere fatores como a legibilidade do código, a flexibilidade e o desempenho.
Links interessantes: