# Styling Components

Course: [Angular](https://www.devtutorials.ai/learn/angular) · Section: Angular Fundamentals
Source: https://www.devtutorials.ai/learn/angular/fundamentals/styling-components

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

<figure className="ngc-fig">
<svg viewBox="0 0 640 216" role="img" aria-label="Global styles.css applies to ProductCard and CartSummary, while each component's own .title rule stays inside that component.">
<defs><marker id="ngc-y1" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M0 0L10 5L0 10z" className="ngc-arrowhead" /></marker></defs><g className="ngc-step ngc-t1"><g className="ngc-node ngc-solid c-orange"><rect x="170" y="8" width="300" height="52" rx="9" /><text x="320.0" y="31" textAnchor="middle" style={{fontSize:"14px"}}>styles.css (global)</text><text className="ngc-sub" x="320.0" y="49" textAnchor="middle">applies to every component</text></g></g><g className="ngc-step ngc-t2"><g className="ngc-node ngc-soft c-blue"><rect x="20" y="110" width="270" height="64" rx="9" /><text x="155.0" y="139" textAnchor="middle" style={{fontSize:"14px"}}>ProductCard</text><text className="ngc-sub" x="155.0" y="157" textAnchor="middle">.title &#123; color: red &#125;</text></g></g><g className="ngc-step ngc-t3"><g className="ngc-node ngc-soft c-green"><rect x="350" y="110" width="270" height="64" rx="9" /><text x="485.0" y="139" textAnchor="middle" style={{fontSize:"14px"}}>CartSummary</text><text className="ngc-sub" x="485.0" y="157" textAnchor="middle">.title &#123; color: blue &#125;</text></g></g><line className="ngc-link ngc-flow c-slate" x1="250" y1="62" x2="155" y2="108" markerEnd="url(#ngc-y1)" /><line className="ngc-link ngc-flow c-slate" x1="390" y1="62" x2="485" y2="108" markerEnd="url(#ngc-y1)" /><text className="ngc-note" x="320" y="146" textAnchor="middle">✕</text><text className="ngc-note" x="320" y="204" textAnchor="middle">Global CSS reaches every component. Component CSS stays inside its own component.</text>
</svg>
<figcaption>Global styles reach every component. Component styles are encapsulated.</figcaption>
</figure>

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

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

```angular runnable title="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:

```text
src/app/price-tag/
├── price-tag.ts
├── price-tag.html
└── price-tag.css
```

Connect the file with **`styleUrl`** (one file):

```ts
@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:

```ts
@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.

| 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:

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; }`.

```angular runnable title="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`:

```ts
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.

```angular runnable title="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.

```angular runnable title="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.

```angular runnable title="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.

```css
:host-context(.dark) .label {
  color: white;
}
```

This means: "Inside this component, style `.label` when some parent element has the class `dark`."

```angular runnable title="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()`:

```css
: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.

```angular runnable title="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.

```angular runnable title="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

<div className="ngc-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 `./` |

</div>

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