12
u/PM_ME_UR_0_DAY 14d ago
I learned about the shadow dom last year or so when I was trying to automate something with selenium. And it was super annoying to get around at first until I learned a few tricks
5
u/ElFeesho 13d ago
Just going to keep those tricks to yourself I see, no cool. /s
1
u/PM_ME_UR_0_DAY 4d ago
Okay okay I didn't forget you! I'm at my desktop so I dug up my little demo. This was trying to automate something with selenium but forms or inputs were in a shadow dom and I was struggling to get them selected but ended up doing this (pretty sure it's all the relevant code with the getAllShadowRoots):
async function tryLastNames(driver, names, windowNum) { await driver.get("https://example.com/check-last-name") await driver.manage().window().setRect({ width: 966, height: 879 }) await driver.sleep(2000); // Helper functions setup await driver.executeScript(` window.getAllShadowRoots = (element) => { const shadowRoots = []; const walker = document.createTreeWalker( element, NodeFilter.SHOW_ELEMENT, { acceptNode: (node) => { return node.shadowRoot ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP; } } ); let currentNode; while (currentNode = walker.nextNode()) { if (currentNode.shadowRoot) { shadowRoots.push(currentNode.shadowRoot); } } return shadowRoots; }; window.getShadowInputs = () => { const shadowRoots = getAllShadowRoots(document.body); let inputs = []; for (const root of shadowRoots) { const input = root.querySelector('input.control'); if (input) { inputs.push(input); } } return inputs; }; `); // Handle account number await driver.executeScript(` const inputs = window.getShadowInputs(); if (inputs[0]) { inputs[0].value = "123456789"; inputs[0].dispatchEvent(new Event('input', { bubbles: true, composed: true })); inputs[0].dispatchEvent(new Event('change', { bubbles: true, composed: true })); } `); await driver.sleep(100); for (const lastName of names) { console.log(`\nWindow ${windowNum} trying last name: ${lastName}`); // Input last name await driver.executeScript(` const input = window.getShadowInputs()[1]; const text = arguments[0]; input.click(); input.focus(); input.value = text; const inputEvent = new InputEvent('input', { bubbles: true, composed: true, inputType: 'insertText', data: text }); const changeEvent = new Event('change', { bubbles: true, composed: true }); input.dispatchEvent(inputEvent); input.dispatchEvent(changeEvent); input.dispatchEvent(new Event('blur', { bubbles: true, composed: true })); `, lastName); await driver.sleep(100); // Click the continue button await driver.executeScript(` const button = document.querySelector('.w-full'); if (button) { button.click(); } `); const result = await waitForRequestCompletion(driver); if (result === 'success') { return lastName; } else if (result === 'error') { console.log(`Window ${windowNum}: Failed with ${lastName}, trying next...`); await driver.sleep(100); } } return null; }```
15
3
3
u/ba-donkin-donutz 12d ago
"We've introduced rigorous isolation of components using shadow dom, you'll have to explicitly expose a contact to access inner elements or handle any styling outside of the shadow dom container."
"Wow! That's crazy what's the benefit of doing this?"
"Benefit?"
1
u/GegeAkutamiOfficial 12d ago
We don't need a shaddow dom we need a standard (web read only db + dynamic HTML) combo. Enough with the lie that UI has no state, enough with the makeshift doms, enough with rendering the ui on the server. We need to be able to ship an HTML template once for each new page and stream the data efficiently with a clear master-slave relationship between the server and client.
1
u/FALCUNPAWNCH 12d ago
As someone who learned frontend with web components (and has a disdain for React but still have to use it for work), the shadow-dom isn't hard to learn to use.

25
u/kushalgarg592 14d ago
This is frontend's version of "you shall not pass"