How to access an element deep inside shadow-root

2.4k views Asked by At

How can I access an element which is deep inside the shadow-root?

<vaadin-combo-box>
        #shadow-root
            <vaadin-text-field id="input">
                <vaadin-combo-box-dropdown-wrapper id="overlay">
                    #shadow-root(open)
                        <vaadin-combo-box-dropdown id="dropdown">
                            #shadow-root(open)
                                <vaadin-combo-box-overlay id="overlay">
                                    #shadow-root(open)
                                     <div part="overlay" id="overlay">
                                        <div part="content" id="conent">
                                            #shadow-root(open)
                                                <div id="scroller">
                                                    <iron-list id="selector">
                                                        #shadow-root(open)
                                                            <vaadin-combo-box-item>
                                                                ......
                                                               

I want to style a vaadin-combo-box-item element but I don't know how to access this element.

2

There are 2 answers

5
Igor Nowosad On BEST ANSWER

There's no easy answer to that because you have to access a very deep DOM element.

To make it little bit less painful you have to make a function which access provided shadow dom of element like this:

const getShadowRoot = (elem, selector) => elem.shadowRoot.querySelector(selector);

const vaadinComboBox = getShadowRoot(document, 'vaadin-combo-box');
const vaadinTextField = getShadowRoot(vaadinComboBox, '#input');
const vaadinComboBoxWrapper = getShadowRoot(vaadinTextField, '#overlay');
const vaadinComboBoxDropdown = getShadowRoot(vaadinComboBoxWrapper, '#dropdown');
const vaadinComboBoxOverlay = getShadowRoot(vaadinComboBoxDropdown, '#overlay');
const vaadinComboBoxContent = getShadowRoot(vaadinComboBoxOverlay, '#conent');
const vaadinComboBoxSelector = getShadowRoot(vaadinComboBoxContent, '#selector');
const vaadinComboBoxItem = getShadowRoot(vaadinComboBoxContent, 'vaadin-combo-box-item');

Nevertheless, this amount of shadowDom elements looks like an architectural mistake

0
Bernat Gene On

I couldn't find an answer to get an element at an arbitrary depth. This is what I came up with; you can use a function of the sorts to recursively descend into the shadow DOM, to get either the parent or the element itself:

function* descend(el, sel, parent) {
        if (el.matches(sel)) {
            yield parent ? el.parentElement : el;
        }
        if (el.shadowRoot) {
            for (const child of el.shadowRoot.children) {
                yield* descend(child, sel, parent);
            }
        }
        for (const child of el.children) {
            yield* descend(child, sel, parent);
        }
    };

Example use:

const vid = [...descend(window.parent.document.querySelector("body"), "video", false)][0]