Angular Styling
Angular scopes component CSS by default, while still giving you clear escape hatches — ViewEncapsulation options and dynamic [ngClass]/[ngStyle] bindings — for cases that need broader or more dynamic control.
Component-Scoped Styles
Styles declared in a component's 'styles' array (or a linked stylesheet) are automatically scoped to that component's template. Angular rewrites selectors under the hood so a rule like '.card' in one component never accidentally styles a '.card' element in another.
card.component.ts
import { Component, ViewEncapsulation } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
@Component({
selector: 'app-card',
standalone: true,
encapsulation: ViewEncapsulation.Emulated,
template: `
<div class="card">
<h3>{{ title }}</h3>
<p><ng-content></ng-content></p>
</div>
`,
styles: [`
.card {
border: 1px solid #ddd;
border-radius: 8px;
padding: 1rem;
}
h3 {
margin: 0 0 0.5rem;
color: #2c3e50;
}
`]
})
export class CardComponent {
title = 'Default Title';
}
bootstrapApplication(CardComponent).catch((err) => console.error(err));
How View Encapsulation Works
ViewEncapsulation controls the strategy Angular uses to scope styles. Emulated is the default and works in every browser without any real Shadow DOM. ShadowDom uses the browser's native Shadow DOM for true style and DOM isolation. None disables scoping entirely, so the styles become global.
Dynamic Classes with [ngClass]
The NgClass directive adds or removes CSS classes based on an expression. Passing an object applies each key whose value is truthy; this is the cleanest way to toggle several conditional classes at once from component state.
status-badge.component.ts
import { Component, Input } from '@angular/core';
import { NgClass } from '@angular/common';
import { bootstrapApplication } from '@angular/platform-browser';
@Component({
selector: 'app-status-badge',
standalone: true,
imports: [NgClass],
template: `
<span
class="badge"
[ngClass]="{
'badge--success': status === 'active',
'badge--warning': status === 'pending',
'badge--danger': status === 'failed'
}"
>
{{ status }}
</span>
`,
styles: [`
.badge { padding: 2px 8px; border-radius: 4px; font-size: 0.85rem; }
.badge--success { background: #d4edda; color: #155724; }
.badge--warning { background: #fff3cd; color: #856404; }
.badge--danger { background: #f8d7da; color: #721c24; }
`]
})
export class StatusBadgeComponent {
@Input() status: 'active' | 'pending' | 'failed' = 'active';
}
bootstrapApplication(StatusBadgeComponent).catch((err) => console.error(err));
Dynamic Inline Styles with [ngStyle]
NgStyle sets multiple inline CSS properties from an object expression, which is useful when a value — like a computed width or color — can't be expressed with a fixed CSS class. For a single style or class, the simpler [style.prop] and [class.name] bindings are usually a better fit.
progress-bar.component.ts
import { Component, Input } from '@angular/core';
import { NgStyle } from '@angular/common';
import { bootstrapApplication } from '@angular/platform-browser';
@Component({
selector: 'app-progress-bar',
standalone: true,
imports: [NgStyle],
template: `
<div class="track">
<div
class="fill"
[class.fill--complete]="percent === 100"
[ngStyle]="{ width: percent + '%', backgroundColor: color }"
></div>
</div>
`,
styles: [`
.track { background: #eee; height: 8px; border-radius: 4px; overflow: hidden; }
.fill { height: 100%; transition: width 0.3s ease; }
.fill--complete { opacity: 0.7; }
`]
})
export class ProgressBarComponent {
@Input() percent = 0;
@Input() color = '#4caf50';
}
bootstrapApplication(ProgressBarComponent).catch((err) => console.error(err));
- Prefer [class.name] and [style.prop] bindings for a single conditional class or style.
- Reach for [ngClass]/[ngStyle] when you need several conditions evaluated together from one expression.
- Use CSS custom properties (variables) for theming instead of computing every color in TypeScript.
- Avoid rebuilding the [ngStyle] object on every change detection cycle — precompute it when the underlying data changes.
Exercise: Angular Styling
Where do you define CSS scoped to just one component?