47

Am following this tutorial on transclusion https://scotch.io/tutorials/angular-2-transclusion-using-ng-content

However there is no mention on how to style elements that end up replacing ng-content.

It seems that I can only target those element in the css if preceeded by the /deep/ keyword, which is normally used when targeting a nested component. Is this correct?

Kamil Naja
  • 6,267
  • 6
  • 33
  • 47
user1275105
  • 2,643
  • 5
  • 31
  • 45

4 Answers4

38

Content inside <ng-content> is insulated from the component. It can't see the component's attributes or styling.

If you do need to style it, and sometimes you will, you have two options:

1. Just write CSS

You can create a regular CSS file and style the content like that. You are almost certainly using the shadow DOM polyfill. Regular CSS will see through the polyfill and just style the element. Say you have an app-sidebar. You could write:

app-sidebar p {
  color:red;
}

If you are using ng-cli, any rules you write in style.scss will be global.

2. Use the :host /deep/ selector

If you want to use the shadow DOM polyfill and style your components using the style or styleUrls attribute of the Component decorator, select the element with :host, then ignore the shadow DOM polyfill with the /deep/ child selector.

  • :host will select the element.
  • /deep/ will select elements without adding the mock shadow DOM attribute selector to the nested selectors.

Put them together and you can select all elements nested inside the host component element, regardless of where they are declared.

like so:

:host /deep/ p {
  color:red;
}
superluminary
  • 47,086
  • 25
  • 151
  • 148
  • 8
    Option 2 is the best answer in my opinion, however it should now be updated to use ::ng-deep, [as explained here in the angular documentation](https://angular.io/guide/component-styles#deprecated-deep--and-ng-deep): `The shadow-piercing descendant combinator is deprecated and support is being removed from major browsers and tools. As such we plan to drop support in Angular (for all 3 of /deep/, >>> and ::ng-deep). Until then ::ng-deep should be preferred for a broader compatibility with the tools.` – vince Oct 05 '17 at 15:22
  • 5
    All the "deep" selectors have been depreciated by now. – Fill Dec 10 '17 at 16:02
  • 1
    @Fill - I know, I'm still looking for a viable alternative. – superluminary Dec 11 '17 at 09:00
  • @superluminary ehh yeahh... I'm afraid there are only 2 solutions here: use :host & :host-context classes from inside each component and style components depending on its surrounding (most preferable as it decouples components) or use main styles.css / style.scss file - styles there are applied globally and affect even deepest components (no need for :deep at all) Hope that will help ;-) – Fill Dec 12 '17 at 13:09
  • @fill - The future solution involves native support for SASS style mixins, which is *quite* a nice solution. I feel like this is a problem that no-one has really solved yet. – superluminary Dec 13 '17 at 11:12
  • @superluminary hmm who knows... still this is not really a limitation - removal of the deep selector and other shadow-piercing (damn, I love this name!) styles is a logical move from the point of view of "isolated components". It forces devs to approach problems from a different angle - to think about the implementation of components as super-portable elements. At the begin i was like "omg what we will do now"... after few weeks I realised that this is not a big problem ;-) – Fill Dec 14 '17 at 19:44
  • 2
    @fill - Interesting. A button is a super portable element, because it has styling, but you can override that styling from outside. Likewise a dropdown. I'm still struggling to see how preventing a consumer from styling a component makes that component more portable. – superluminary Dec 15 '17 at 10:00
  • @superluminary you see that's where decoupling & separation of concerns comes with help. Make components as ignorant as possible they should accept anything. Example: you have table component as a parent and a base component for buttons. This button component is extended by few other components that from outside looks exactly the same for a parent. Case 1: table contains style that changes the colour of a button child. Case 2: button have a class that checks if the parent is a table and adjusts its colour. Which approach gives less headache & more isolation? – Fill Dec 15 '17 at 23:26
27

This solved my issue

::ng-deep {
    & > * {
         // styles here
    }
}
Suraj Rao
  • 29,388
  • 11
  • 94
  • 103
stackoverflow
  • 1,303
  • 2
  • 21
  • 36
  • Works with TailwindCSS @apply for Angular 11.2 inside component specific scss in a library project. Putting here for future seekers. – Rohith Balaji Apr 25 '21 at 06:21
24

update

::slotted is now supported by all new browsers and can be used with ViewEncapsulation.ShadowDom

https://developer.mozilla.org/en-US/docs/Web/CSS/::slotted

original

::content xxx { ... } might work as well or :host xxx { ... }. The shimming is not very strict or accurate. AFAIK (>>> /deep/ old) ::ng-deep (supported by SASS) and a space do currently the same.

Nicolas
  • 8,077
  • 4
  • 21
  • 51
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • For some reason, I thought I needed `>>>` or `/deep/` but it just works with `:host xxx {...}` – user1275105 Dec 11 '16 at 21:17
  • Actually, ignore previous comment, I still can't get it to work unless I include `/deep/` like this `:host /deep/ xxx {...}` . Is there some sort of setting that needs to be turned on? – user1275105 Dec 11 '16 at 21:28
  • This might have changed at some point so that a space isn't enough anymore. Did you try `::content? There is no setting. – Günter Zöchbauer Dec 12 '16 at 03:51
  • https://angular.io/docs/ts/latest/guide/component-styles.html only mentions `/deep/` – Günter Zöchbauer Dec 12 '16 at 07:12
  • `::content` doesn't work. only `/deep/` works, which is fine but I need to know if this the "correct" way and am not unnecessarily doing it a "hacky" way. – user1275105 Dec 12 '16 at 13:04
  • The whole CSS shimming is a bit hacky currently. I wouldn't worry too much. If it's working you should be fine. I'm pretty sure they will rework this somehow eventually (like support for CSS variables) – Günter Zöchbauer Dec 12 '16 at 13:09
  • Other option using a wrapper div around the ng-content and targeting that instead. – user1275105 Dec 12 '16 at 13:34
  • 1
    That's a valid way as well. – Günter Zöchbauer Dec 12 '16 at 13:43
  • This is pitiful. It almost seems explicitly a **lock-in syntax**. I cannot see any other reason to intentionally allow this into a framework worth its salt. – Cody Apr 27 '18 at 22:34
  • 1
    @Cody I don't understand your comment. These CSS combinators are from the WebComponents spec. – Günter Zöchbauer Apr 28 '18 at 04:10
  • In my case using `:host >>> xxx { ... }` worked just fine! (Angular6) – zolastro Aug 14 '18 at 09:31
  • @GünterZöchbauer I'm sorry to dig up an old topic, but what would be the selector for components not using the shadow dom ? Is using the shadow dom considered the best practice when making reusable components ? –  Dec 10 '18 at 14:58
  • 1
    Hi @trichetriche `::content`. This works for the "shadow DOM" emulated by Angular (if nothing changed recently - don't follow Angular closely - check the CHANGELOG.md in the Angular repo) – Günter Zöchbauer Dec 10 '18 at 15:24
3

As an alternative to the above answers, you can create a directive to be applied to the content, and use the directive to add the styling for the content.

meblum
  • 1,654
  • 12
  • 23