Styling Components in Angular
By Syncfusion®, Inc. · Last updated
Adding CSS to components: inline and external styles, styleUrl and styleUrls, global styles, style encapsulation and its modes, the :host and :host-context() selectors, CSS custom properties, and sharing styles.
Introduction to Component Styling
Component styling means writing CSS for one component: its colours, sizes, spacing and layout. In the Components lesson, you added CSS with the styles property. This lesson shows all the ways to add CSS, and how Angular keeps the CSS of one component away from the others.
Each component can have its own CSS, and the app can also have global CSS that applies to every page.
Real-World Example
An online store has a ProductCard component and a CartSummary component. Both use a CSS class called .title, but with different sizes and colours.
Because Angular limits each component's CSS to that component, the two .title rules never affect each other. The team can change one card's design without breaking the rest of the site.
styles.css (global)applies to every componentProductCard.title { color: red }CartSummary.title { color: blue }✕Global CSS reaches every component. Component CSS stays inside its own component.
Global styles reach every component. Component styles are encapsulated.
Inline vs External Styles
You can write a component's CSS in two places:
- Inline styles: inside the
@Componentdecorator, with thestylesproperty. - External styles: in a separate
.cssfile, connected with thestyleUrlproperty.
| Point | Inline (styles) | External (styleUrl) |
|---|---|---|
| Where the CSS is | In the .ts file | In a .css file |
| Good for | A few short rules | Most components |
| Editor help for CSS | Limited | Full CSS support |
| Created by the CLI | No | Yes: ng generate component creates a .css file |
Both work the same way. Angular treats the CSS identically, and encapsulation applies to both.
Using the styles Property
styles contains CSS as text, written between backticks (`). Use it when the component needs only a few rules.
Inline styles with the styles property
import { Component } from '@angular/core';
@Component({
selector: 'app-price-tag',
template: `<p class="price">$49.99</p>`,
styles: `
.price {
color: white;
background: #16a34a;
display: inline-block;
padding: 4px 12px;
border-radius: 12px;
font-weight: bold;
}
`,
})
export class PriceTag {}
@Component({
selector: 'app-root',
imports: [PriceTag],
template: `
<h3>Wireless Headphones</h3>
<app-price-tag />
<p class="price">This paragraph also has the class "price", but it is not green.</p>
`,
})
export class App {}
The second paragraph has the same class, price, but it is in the App component. The rule in PriceTag does not reach it.
styles can also be an array of texts: styles: ['.a { color: red; }', '.b { color: blue; }']. Angular joins them in order.
Using the styleUrl and styleUrls Properties
For longer CSS, keep it in a separate file next to the component:
src/app/price-tag/
├── price-tag.ts
├── price-tag.html
└── price-tag.css
Connect the file with styleUrl (one file):
@Component({
selector: 'app-price-tag',
templateUrl: './price-tag.html',
styleUrl: './price-tag.css',
})
export class PriceTag {}
Use styleUrls (an array) to connect more than one file:
@Component({
selector: 'app-price-tag',
templateUrl: './price-tag.html',
styleUrls: ['./card-base.css', './price-tag.css'],
})
export class PriceTag {}
- The path starts with
./, which means "in the same folder as this.tsfile". - In
styleUrls, the files are applied in order. A later file can override a rule from an earlier file. - Older projects always use
styleUrls. Newer CLI projects usestyleUrlfor one file.
The practice blocks keep all the code in one file, app.ts, so they use the styles property. In your own CLI projects, use styleUrl with a .css file.
Component Styles vs Global Styles
Global styles are in src/styles.css. Angular adds this file to the whole app, so its rules apply to every component. Use it for things that must be the same everywhere:
- The font and the background of the page (
body) - Default styles for links, buttons and headings
- Shared CSS classes, such as
.erroror.container
Component styles apply only to their own component. Use them for the design of that component.
| Point | Global styles (styles.css) | Component styles |
|---|---|---|
| Applies to | The whole app | One component |
| Good for | Fonts, colours of body, shared classes | The layout and look of one component |
| Risk | A rule can change elements in unexpected places | Low, thanks to encapsulation |
The project in each practice block also has src/styles.css. Open it in the explorer, add body { background: #fef3c7; }, and click Run: every component gets the background.
Understanding Style Encapsulation
Encapsulation means "keeping something inside its own box". With style encapsulation, the CSS of a component works only inside that component's template.
Angular does this automatically:
- It gives every element in a component's template an extra attribute, for example
_ngcontent-abc-1. - It changes each CSS rule of the component so it only matches elements with this attribute.
p { color: red; }becomesp[_ngcontent-abc-1] { color: red; }.
Two components, two p rules
import { Component } from '@angular/core';
@Component({
selector: 'app-alert',
template: `<p>⚠ Your session will end in 5 minutes.</p>`,
styles: `p { color: #b91c1c; font-weight: bold; }`,
})
export class Alert {}
@Component({
selector: 'app-tip',
template: `<p>💡 Save your work often.</p>`,
styles: `p { color: #1d4ed8; font-style: italic; }`,
})
export class Tip {}
@Component({
selector: 'app-root',
imports: [Alert, Tip],
template: `
<app-alert />
<app-tip />
<p>A paragraph in App, with no component style.</p>
`,
})
export class App {}
Both components style the p element, but each rule changes only its own paragraph. Open the browser's developer tools (F12) and look at the Elements tab to see the _ngcontent-... attributes.
View Encapsulation Modes
The encapsulation property of @Component chooses how Angular limits the CSS. Import ViewEncapsulation from @angular/core:
import { Component, ViewEncapsulation } from '@angular/core';
@Component({
selector: 'app-banner',
template: `...`,
encapsulation: ViewEncapsulation.None,
})
export class Banner {}
| Mode | What it does | When to use it |
|---|---|---|
Emulated | Limits the CSS to the component with extra attributes | Almost always. This is the default |
None | No limit: the CSS becomes global | Rarely, for example to style HTML from another library |
ShadowDom | Uses the browser's Shadow DOM to separate the component completely | Components used outside Angular |
ViewEncapsulation.Emulated
This is the default mode. You do not need to write it. It emulates (imitates) a separate box with the extra attributes you saw above. Global styles still apply inside the component.
ViewEncapsulation.None
With None, Angular does not change the CSS. The component's rules are added to the page as global CSS, so they affect every matching element in the app.
ViewEncapsulation.None makes CSS global
import { Component, ViewEncapsulation } from '@angular/core';
@Component({
selector: 'app-banner',
template: `<p class="highlight">Banner: Big sale this weekend!</p>`,
styles: `.highlight { background: #fde047; padding: 4px; }`,
encapsulation: ViewEncapsulation.None,
})
export class Banner {}
@Component({
selector: 'app-root',
imports: [Banner],
template: `
<app-banner />
<p class="highlight">App: this paragraph is yellow too, because the Banner's rule is global.</p>
`,
})
export class App {}
Delete the encapsulation line and click Run. Now only the banner is yellow.
ViewEncapsulation.ShadowDom
With ShadowDom, the browser puts the component's elements into a separate shadow tree. It is a real wall:
- The component's CSS cannot leave the component.
- Global CSS from
styles.csscannot enter the component either.
ViewEncapsulation.ShadowDom
import { Component, ViewEncapsulation } from '@angular/core';
@Component({
selector: 'app-widget',
template: `<p class="box">I am inside a Shadow DOM.</p>`,
styles: `.box { border: 2px dashed #7c3aed; padding: 8px; color: #7c3aed; }`,
encapsulation: ViewEncapsulation.ShadowDom,
})
export class Widget {}
@Component({
selector: 'app-root',
imports: [Widget],
template: `
<app-widget />
<p class="box">Outside: the .box rule of Widget does not reach me.</p>
`,
})
export class App {}
In the developer tools, the widget's paragraph is inside a #shadow-root element.
Use ViewEncapsulation.None only when you must. Its rules affect the whole app, and two components with the same class name can then change each other's design.
Using the :host Selector
The host element is the element of the component's selector itself, for example <app-card>. The component's own CSS cannot select it with app-card { }, because the host element is in the parent's template.
Use :host to style the host element from inside the component:
:host { ... }styles the host element.:host(.selected) { ... }styles the host element only when it has the classselected.
Custom elements such as <app-card> are display: inline by default. Set :host { display: block; } so that width, padding and margin work as expected.
Styling the host element with :host
import { Component } from '@angular/core';
@Component({
selector: 'app-card',
template: `<p>Product card</p>`,
styles: `
:host {
display: block;
border: 1px solid #d1d5db;
border-radius: 8px;
padding: 0 12px;
margin-bottom: 8px;
}
:host(.selected) {
border-color: #c3002f;
background: #fff1f2;
}
`,
})
export class Card {}
@Component({
selector: 'app-root',
imports: [Card],
template: `
<app-card />
<app-card class="selected" />
<app-card [class.selected]="isSelected" (click)="isSelected = !isSelected" />
`,
})
export class App {
isSelected = false;
}
The second card has the class selected all the time. Click the third card: class binding adds and removes the class, and :host(.selected) changes its style.
Using the :host-context() Selector
:host-context(.name) styles the component when any parent element above it has the class name. A common use is a dark theme: the app puts the class dark on an outer element, and each component changes its own colours.
:host-context(.dark) .label {
color: white;
}
This means: "Inside this component, style .label when some parent element has the class dark."
A dark theme with :host-context()
import { Component } from '@angular/core';
@Component({
selector: 'app-badge',
template: `<span class="label">New</span>`,
styles: `
.label { background: #e5e7eb; color: #111827; padding: 2px 10px; border-radius: 10px; }
:host-context(.dark) .label { background: #374151; color: #f9fafb; }
`,
})
export class Badge {}
@Component({
selector: 'app-root',
imports: [Badge],
template: `
<button (click)="dark = !dark">Switch theme</button>
<div [class.dark]="dark" class="panel">
<p>Theme: {{ dark ? 'dark' : 'light' }} <app-badge /></p>
</div>
`,
styles: `
.panel { padding: 8px 12px; border-radius: 8px; }
.dark { background: #111827; color: #f9fafb; }
`,
})
export class App {
dark = false;
}
Badge does not know about the button. It only checks if a parent element has the class dark.
Using CSS Custom Properties in Components
A CSS custom property is a variable in CSS. Its name starts with two dashes, and you read it with var():
:root {
--brand-color: #c3002f; /* define */
}
.button {
background: var(--brand-color); /* use */
}
Custom properties are inherited: a value set on a parent element is available in every element inside it, and encapsulation does not block them. So they are the best way to let a parent change the design of a child component.
- The child component reads a variable and gives a default value:
var(--card-color, #1d4ed8). The second value is used when the variable is not set. - The parent sets the variable on an element around the child, or on the child's host element.
Theming a component with CSS custom properties
import { Component } from '@angular/core';
@Component({
selector: 'app-button',
template: `<button class="btn">Buy now</button>`,
styles: `
.btn {
background: var(--btn-color, #1d4ed8);
color: white;
border: none;
padding: 6px 14px;
border-radius: 6px;
}
`,
})
export class AppButton {}
@Component({
selector: 'app-root',
imports: [AppButton],
template: `
<p>Default: <app-button /></p>
<p class="sale">Sale section: <app-button /></p>
<p>Set by style binding: <app-button [style.--btn-color]="'#16a34a'" /></p>
`,
styles: `.sale { --btn-color: #c3002f; }`,
})
export class App {}
The same AppButton has three colours. Only the value of --btn-color changes; its CSS stays the same.
Define your brand colours and sizes once, as custom properties on :root in styles.css. Every component can then use var(--brand-color), and you can change the whole design in one place.
Sharing and Reusing Styles Across Components
When several components need the same CSS, do not copy it into each one. Use one of these ways:
| Way | How | Use it for |
|---|---|---|
| Global classes | Put the rules in styles.css, for example .card { ... } | Classes that many components use in their templates |
| CSS custom properties | Define --brand-color on :root, read it with var() | Colours, sizes and spacing |
| A shared CSS file | List it first in styleUrls: ['../shared/card.css', './product.css'] | Rules that a group of components shares, still encapsulated |
| A shared constant | Export the CSS text from a .ts file and add it to styles: [...] | The same idea when all code is in TypeScript |
The next example uses a shared constant. Both components add CARD_STYLES to their own styles array, so each gets an encapsulated copy of the same rules.
Reusing the same styles in two components
import { Component } from '@angular/core';
// In a real project, this is in its own file, for example shared/card-styles.ts
export const CARD_STYLES = `
.card { border: 1px solid #d1d5db; border-radius: 8px; padding: 8px 12px; margin-bottom: 8px; }
.card h4 { margin: 0 0 4px; }
`;
@Component({
selector: 'app-product-card',
template: `<div class="card"><h4>Laptop</h4><p>$899</p></div>`,
styles: [CARD_STYLES, `.card { border-color: #2563eb; }`],
})
export class ProductCard {}
@Component({
selector: 'app-review-card',
template: `<div class="card"><h4>⭐⭐⭐⭐⭐</h4><p>Great battery life.</p></div>`,
styles: [CARD_STYLES, `.card { border-color: #f59e0b; }`],
})
export class ReviewCard {}
@Component({
selector: 'app-root',
imports: [ProductCard, ReviewCard],
template: `<app-product-card /><app-review-card />`,
})
export class App {}
Each component adds one rule after CARD_STYLES to change only the border colour. Later rules override earlier ones.
Common Mistakes
| Mistake | What you see | Fix |
|---|---|---|
| Styling a child component's elements from the parent's CSS | The rule has no effect | Style them inside the child, or use a CSS custom property |
app-card { ... } in the card's own styles | The host element is not styled | Use :host { ... } |
| Width or margin on a component does not work | The host element is inline | Add :host { display: block; } |
encapsulation: ViewEncapsulation.None everywhere | Components change each other's design | Keep the default Emulated |
| Copying the same CSS into many components | Changes must be made in many files | Use global classes, custom properties or a shared file |
Wrong path in styleUrl | Build error: the file cannot be found | Use a path relative to the .ts file, starting with ./ |
Check Yourself
Exercises
What to Remember
- Add component CSS with
styles(inline) orstyleUrl/styleUrls(external files). Put app-wide CSS insrc/styles.css. - Angular encapsulates component CSS by default (
Emulated).Nonemakes it global, andShadowDomuses the browser's Shadow DOM. Use:hostto style the component's own element and:host-context()to react to a parent's class. - Use CSS custom properties to theme components from outside, and share styles with global classes, custom properties or shared files instead of copying CSS.
Next: Directives, how to add, remove, repeat and restyle elements from the template.