Skip to content

Add support for ::slotted() selector (previously known as ::content) for ViewEncapsulation.Emulated and ViewEncapsulation.Native #11595

Closed

Description

@rvalimaki

I'm submitting a ... (check one with "x")

[ ] bug report => search github for a similar issue or PR before submitting
[*] feature request
[ ] support request => Please do not submit support request here, instead see https://github.com/angular/angular/blob/master/CONTRIBUTING.md#question

Current behavior
Neither ::slotted(some-ng-content-projected-child) nor ::content doesn't have any effect.

Expected behavior
Current Shadow DOM specification (or W3C Working Draft) has defined "slot" (previously "content") tag, which "ng-content" tries to emulate. Styling slotted (or ng-contained...) components should be possible using ::slotted() selector.

Specs for ":slotted()":
https://drafts.csswg.org/css-scoping/#selectordef-slotted

An usage example taken from https://developers.google.com/web/fundamentals/primers/shadowdom/

Styling distributed nodes

::slotted(compound-selector) matches nodes that are distributed into a "slot".

Let’s say we’ve created a name badge component:

<name-badge>
  <h2>Eric Bidelman</h2>
  <span class="title">
    Digital Jedi, <span class="company">Google</span>
  </span>
</name-badge>

The component’s shadow DOM can style the user’s "h2" and .title:

<style>
::slotted(h2) {
  margin: 0;
  font-weight: 300;
  color: red;
}
::slotted(.title) {
   color: orange;
}
/* DOESN'T WORK (can only select top-level nodes).
::slotted(.company),
::slotted(.title .company) {
  text-transform: uppercase;
}
*/
</style>

As of now, shimming is of course needed, since there is no native support for "slotted", at least not for most browsers.

Reproduction of the problem
You can find a plunker about the issue:
https://plnkr.co/edit/4rFsfL9HBY87cesDgN9P?p=preview

What is the motivation / use case for changing the behavior?
There are several probable use cases for this, including that clear example from developers.google.com Shadow DOM guide.

Most critical one is as I do see the issue, is that you have several native "components" (h1, tr, td) projected into your component using "ng-content" ("slot"), that act's as a custom container, such as in above "name-badge" example.

A specific example I have is that I do have a custom table-like component, and want to style contained "tr" elements accordingly. Eg. I would like to set all odd rows for that said table-like components to have a dark gray background, and all even rows to have a light yellow background. I honestly don't know how to handle that without using ::slotted() (or ::content) or alternatively ditch the ViewEncapsulation completely, which is not desired.

In addition to "slot" / "::slotted()", there is a partially overlapping feature of Shadow DOM style hooks, but support for that is also missing for Angular2: #10663

In previous Angular2 versions you were able to style derived ng-contents as expected, but that was considered a misbehavior and "fixed" for RC.5 or RC.6, as you can see from comments for closed bug #7400

With Shadow-piercing combinator ">>>" (previously "/deep/") being deprecated, "slotted" and Shadow DOM style hooks are the only remaining hope for non-insane way for styling contained native elements, without breaking the view encapsulation.
#5345 is also related to this issue.

Please tell us about your environment:

  • Angular version: 2.0.0-rc.X
    2.0.0.-rc.7
  • Browser: [all | Chrome XX | Firefox XX | IE XX | Safari XX | Mobile Chrome XX | Android X.X Web Browser | iOS XX Safari | iOS XX UIWebView | iOS XX WKWebView ]
    Chrome 52, Firefox 48, IE 11, Edge. All, I guess.
  • Language: [all | TypeScript X.X | ES6/7 | ES5]
    all
  • Node (for AoT issues): node --version =
    Not relevant

Activity

  1. added
    featureLabel used to distinguish feature request from other issues
    area: coreIssues related to the framework runtime
    on Sep 14, 2016
  2. tbosch commented on Nov 5, 2016

    @tbosch
    Contributor

    Implementation hint:

    • When we create the elements in the original place, we already have a reference to the component view and know the encapsulation id of that component
    • So we can add an attribute ngprojected-<comp-id> to it
    • Then convert ::slotted to select elements with this attribute and the current component id.
  3. added
    open for contributionsAn issue that is suitable for a community contributor (based on its complexity/scope).
    on Nov 5, 2016
  4. ovangle commented on Nov 26, 2016

    @ovangle

    Does it make sense to use ::slotted if <slot> isn't supported when using ViewEncapsulation.Native?

  5. rvalimaki commented on Nov 26, 2016

    @rvalimaki
    Author

    Oh well, all html tags got stripped in above comment. Let's try again:

    I haven't used native view encapsulation, but <ng-content> is an Angular2 spesific version of <host> tag, formerly known as <content> tag.

    For some reason, Angular2 team did choose to not rename the <ng-content> to <ng-host> when the native <content> tag was renamed to <host> tag.

  6. ovangle commented on Nov 28, 2016

    @ovangle

    @rvalimaki
    Now that all the browser vendors have agreed to ship v1 of the shadow DOM api, it would make more sense if the angular api was updated to reflect it, rather than mangling the ::slotted selector to work with angular.

    It would be possible to deprecate <ng-content> and associated classes gracefully in favour of <ng-slot> and to keep the /deep/ combinator for ng-content as-is during the deprecation period.

    Named slots have a distinct advantage over ng-content in angular anyway, since ContentChild(string) selects by template reference variable, but <ng-content> selects by css selector. If <ng-slot> was used, the template reference variable would determine the named slot into which the component/element should be distributed.

  7. rvalimaki commented on Nov 28, 2016

    @rvalimaki
    Author

    @ovangle

    Fair enough. But I'd say then Angular2 should support ::content selector with <ng-content> until the change. For a developer perspective, I'd rather haver either working ::content or ::slotted, but the current situation is when we lack support for both of the ways is not that good.

    Given that it's already said so that /deep/ or >>> is already deprecated and will be totally removed in the future without any other feature that could even remotely replace it, I do not continue using that way. Sadly, as current status of affairs is as it is, we had to fall back to using ViewEncapsulation.None for all generic container type components. I'd say that's about 5-10% of all our components we use, so probably that's not that big issue.

  8. titusfx commented on Jul 12, 2017

    @titusfx

    I was redirected from here. And I can't find the solution.
    How can I do an equivalent of .some-class > * { /*styles*/} where the child of .som-class is an <ng-content> ( where

    /deep/ and >>> are deprecated

    ? )

  9. ericmartinezr commented on Jul 12, 2017

    @ericmartinezr
    Contributor
  10. rvalimaki commented on Jul 21, 2017

    @rvalimaki
    Author

    @ericmartinezr

    While that feature supporting ::ng-deep is something, it's kind of a step backwards, as it's already deprecated when released and will be removed in the future. Also browsers will not include such or similar functionality in the future at all, though they do include the "lite-version" of that functionality using the ::slotted(), as described in this bug report.

  11. added this to the Backlog milestone on Jan 23, 2018
  12. robwormald commented on Sep 15, 2018

    @robwormald
    Contributor

    Shadow DOM V1 support is in, so ::slotted is now supported natively.

  13. rvalimaki commented on Sep 15, 2018

    @rvalimaki
    Author

    @robwormald:

    Excellent news that .Native ::slotted() is now supported.

    What about implementinh ::slotted() also for ViewEncapsulation.Emulated so that emulation would be more 1:1?

  14. zoechi commented on Sep 15, 2018

    @zoechi
    Contributor

    Shouldn't ViewEncapsulation.Emulated just be deprecated now that all browsers support Native?

  15. emilio-martinez commented on Sep 16, 2018

    @emilio-martinez
    Contributor

    @zoechi Shadow Dom v1 isn't supported at all in IE and Edge, hasn't reached stable on Firefox, and seems to be buggy in Safari (https://caniuse.com/#feat=shadowdomv1), so the support is definitely not there yet.

    Regardless, I think even if it did, the usefulness of Emulated encapsulation would not be obviated; for example, Shadow Dom doesn't have a standard way of being serialized yet, so Emulated would still be helpful when paired with SSR

  16. oliverjanik commented on Oct 9, 2018

    @oliverjanik

    @robwormald Can you stop closing unresolved issues?

    The title clearly states ::slotted support for ViewEncapsulation.Emulated and that does not work.

  17. cyraid commented on Oct 10, 2018

    @cyraid
    Contributor

    So it being closed, it means I can use ::slotted instead of ::ng-deep?

  18. rvalimaki commented on Oct 12, 2018

    @rvalimaki
    Author

    @oliverjanik @cyraid

    ::slotted is now partially implemented, when using ViewEncapsulation.Native, but not with ViewEncapsulation.Emulated.

    What I did request in original request was implementation for both .Native (fixed) and .Emulated (not fixed). As I thought we could use .Emulated until everything works perfectly in .Native, and then finally migrate to .Native, the whole idea being .Emulated emulating .Native as closely as possible to make such migration possible.

    We already abandoned the idea of using ::slotted as there was not going to be quick fix for the issue, and started using ViewEncapsulation.None for most of our "container type" components. Obviously that sucks a bit more than a bit, but works to some degree. ::slotted support itself is a dumbed down version of ::ng-deep, but that's beyond Angular team, as that's how web standards ended up and they say they had good performance etc. related reasons for that.

    Heads up @robwormald

  19. angular-automatic-lock-bot commented on Sep 14, 2019

    @angular-automatic-lock-bot

    This issue has been automatically locked due to inactivity.
    Please file a new issue if you are encountering a similar or related problem.

    Read more about our automatic conversation locking policy.

    This action has been performed automatically by a bot.

  20. locked and limited conversation to collaborators on Sep 14, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: coreIssues related to the framework runtimefeatureLabel used to distinguish feature request from other issuesfreq1: lowopen for contributionsAn issue that is suitable for a community contributor (based on its complexity/scope).

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions