3

As far as I know, the /deep selector is deprecated to select shadow dom children. So I'm looking for another solution.

CSS scoping looks to provide solutions for ascending selector, but not for descending one.

Given this dom :

<script>
    $('.child').addClass('reached');
</script>
<div id="parent">
    #shadow-root
        <div class="child"></div>
    /shadow-root
</div>

How can I write the selector in the script to reach the .child element ?

Thank you for your help

hadf
  • 279
  • 2
  • 5
  • 15
  • Do you mean something like :slotted? If so, check out https://stackoverflow.com/questions/27622605/what-is-the-content-slotted-pseudo-element-and-how-does-it-work/27629265#27629265 Also start reading at https://www.w3.org/TR/dom41/#shadow-tree-slots and https://www.w3.org/TR/css-scoping-1/#selectors-data-model – TylerH Jun 25 '18 at 19:19
  • May be am I wrong, but I didn't success to use ::slotted to reach descending nodes – hadf Jun 25 '18 at 19:55
  • jQuery was never designed to use shadow DOM. It is best to avoid it when working with Web components and shadow DOM. Use the native APIs like `querySelector` and `querySelectorAll`. They will save you lots of confusion and difficulty. – Intervalia Jun 26 '18 at 14:18
  • Ok, so do you suggest a solution with querySelector ? – hadf Jun 26 '18 at 14:34
  • A single `querySelector` can not penetrate shadowDOM. Instead you need to get to the component with one `querySelector` and then use a second `querySelector` on the `shadowRoot` of the element. – Intervalia Jun 27 '18 at 15:02
  • The real question is WHY are you trying to do this? A component should play with its children and nothing else should. If something on the outside is playing with the component's children then you are breaking several rules on clean coding. The only time I can see *needing* to do this is for testing. – Intervalia Jun 27 '18 at 15:05

1 Answers1

5

How can I write the selector in the script to reach the .child element?

To reach an element in the Shadow DOM, you should use the shadowRoot property on the element.

var parent = document.querySelector( '#parent' )
var child = parent.shadowRoot.querySelector( '#child' )
child.classList.add( 'reached' )

Note : the Shadow DOM must have been created in the open mode.

var sh = parent.attachShadow( { mode: 'open' } )

var parent = document.querySelector( '#parent' )
var sh = parent.attachShadow( { mode: 'open' } )
sh.innerHTML = `<style>
                    div.reached { color: green }
                </style>
                <div id="child">Child</div>
                `
var child = parent.shadowRoot.querySelector( '#child' )
child.classList.add( 'reached' )
<div id="parent">
</div>

Note: ::slotted is needed only if you have elements in the light DOM revealed with <slot>.


Is there alternative to /deep selector?

Short answer is no. Since Shadow DOM is aimed at isolating Shadom DOM from the main page, /deep was kind of an heresy.

A very new proposal, with ::part and ::theme pseudo-elements could give some control back, but it's not to be implemented soon.

Until then the main workaround is to use CSS custom properties.

However the 2 solutions must be implemented by the Web Component designer and cannot be overrided otherwise.

Supersharp
  • 29,002
  • 9
  • 92
  • 134
  • Hello, thank you for your response. Your solution is a JS solution. Is it possible to have a CSS solution. I mean a solution based on the selector. – hadf Jun 26 '18 at 14:32
  • 1
    No for global CSS (unless your shadowed element was designed to handle specific adhoc CSS variables). Yes maybe for local CSS in shadow DOM. It depends on your needs (but in your question it seems that you want a global, /deep equivalent and the answer is no. – Supersharp Jun 26 '18 at 16:15
  • @hadf Your welcome. I've updated my answer. Don't hesitate to post a new question with a concrete use case. There are different answer (CSS variables but also other workaround) depending of the situation. Example: https://stackoverflow.com/a/47633167/4600982 – Supersharp Jun 26 '18 at 16:34