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 @Component decorator, with the styles property.
  • External styles: in a separate .css file, connected with the styleUrl property.
PointInline (styles)External (styleUrl)
Where the CSS isIn the .ts fileIn a .css file
Good forA few short rulesMost components
Editor help for CSSLimitedFull CSS support
Created by the CLINoYes: 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 .ts file".
  • 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 use styleUrl for 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 .error or .container

Component styles apply only to their own component. Use them for the design of that component.

PointGlobal styles (styles.css)Component styles
Applies toThe whole appOne component
Good forFonts, colours of body, shared classesThe layout and look of one component
RiskA rule can change elements in unexpected placesLow, 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:

  1. It gives every element in a component's template an extra attribute, for example _ngcontent-abc-1.
  2. It changes each CSS rule of the component so it only matches elements with this attribute. p { color: red; } becomes p[_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 {}
ModeWhat it doesWhen to use it
EmulatedLimits the CSS to the component with extra attributesAlmost always. This is the default
NoneNo limit: the CSS becomes globalRarely, for example to style HTML from another library
ShadowDomUses the browser's Shadow DOM to separate the component completelyComponents 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.css cannot 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 class selected.

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:

WayHowUse it for
Global classesPut the rules in styles.css, for example .card { ... }Classes that many components use in their templates
CSS custom propertiesDefine --brand-color on :root, read it with var()Colours, sizes and spacing
A shared CSS fileList it first in styleUrls: ['../shared/card.css', './product.css']Rules that a group of components shares, still encapsulated
A shared constantExport 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

MistakeWhat you seeFix
Styling a child component's elements from the parent's CSSThe rule has no effectStyle them inside the child, or use a CSS custom property
app-card { ... } in the card's own stylesThe host element is not styledUse :host { ... }
Width or margin on a component does not workThe host element is inlineAdd :host { display: block; }
encapsulation: ViewEncapsulation.None everywhereComponents change each other's designKeep the default Emulated
Copying the same CSS into many componentsChanges must be made in many filesUse global classes, custom properties or a shared file
Wrong path in styleUrlBuild error: the file cannot be foundUse a path relative to the .ts file, starting with ./

Check Yourself

Exercises

What to Remember

  • Add component CSS with styles (inline) or styleUrl / styleUrls (external files). Put app-wide CSS in src/styles.css.
  • Angular encapsulates component CSS by default (Emulated). None makes it global, and ShadowDom uses the browser's Shadow DOM. Use :host to 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.