What is Shadow DOM?
Shadow DOM is a web standard that allows developers to create encapsulated and isolated DOM trees inside web components. It provides a way to attach a hidden "shadow tree" to an element, separating the component’s internal structure, styles, and behavior from the rest of the document.
This encapsulation prevents external CSS or JavaScript from accidentally affecting the component’s internal elements and vice versa, ensuring better reusability and modularity.
A shadow root can be created in open mode, where it is accessible through JavaScript using element.shadowRoot, or in closed mode, where it is completely hidden from outside scripts. While this makes web components more robust and self-contained, it introduces challenges for automation and testing tools because elements inside the shadow tree are not part of the main DOM and require special handling to be accessed.
In essence, the Shadow DOM is the foundation of modern Web Components, enabling developers to build custom, maintainable UI elements with true style and DOM encapsulation.
Challenges with Shadow DOM in Automation
Because elements inside Shadow DOM are not part of the regular DOM, traditional selectors like page.locator("selector")
won't work directly unless you pierce through the shadow boundary.
Some more challenges include:
1. Encapsulation of DOM
- Elements inside a Shadow DOM are not exposed to the main document’s DOM tree.
That means:
- document.querySelector() cannot directly find elements inside shadow roots.
- Traditional CSS selectors don’t cross shadow boundaries.
2. Dynamic Shadow Roots
- Many web components attach shadow roots dynamically at runtime (e.g., via this.attachShadow({ mode: 'open' }) in JavaScript).
- Automation scripts may fail if the Shadow DOM isn’t yet attached when your test runs.
3. Closed Shadow DOM
Shadow roots can be created in two ways:
- open → accessible via element.shadowRoot
- closed → completely hidden from scripts
With closed shadow DOM, Playwright or other tools cannot pierce inside at all. Only developers who wrote the component can expose test hooks.
4. Slower Locator Resolution
- Playwright has special support (locator().getByRole(), locator().locator(), etc.) that can pierce open shadow DOM.
- But chaining through deep/nested components can lead to fragile selectors if the structure changes.
5. Cross-browser Differences
- While Playwright smooths over some gaps, browsers differ in their handling of shadow DOM and accessibility tree.
- Example: Some browsers may expose shadow content differently to screen readers → automation relying on ARIA roles may behave inconsistently.
Handling Shadow DOM in Playwright Java
To handle Shadow DOM, you can use:
locator().evaluateHandle()
to get the shadow root.
- Then find the element inside that shadow root.
Sample Scenario
Let's say we want to automate a website that contains this structure:
<custom-element> #shadow-root <button id="myButton">Click Me</button> </custom-element>
Here, below are the steps we are performing in code.
import com.microsoft.playwright.*; public class ShadowDOMExample { public static void main(String[] args) { try (Playwright playwright = Playwright.create()) { Browser browser = playwright.chromium().launch(new BrowserType.LaunchOptions().setHeadless(false)); Page page = browser.newPage(); // Navigate to a sample page with Shadow DOM page.navigate("https://books-pwakit.appspot.com/"); // Wait for the shadow host element Locator host = page.locator("book-app");
// Access shadow root and query inside Locator searchInput = host.locator("#input"); // Interact with the element inside shadow DOM searchInput.fill("Playwright"); } } }
"#input"
is called deep selector in Playwright. It helps to pierce through shadow DOM boundaries.Use
locator(">>> selector")
to access nested shadow DOM elements.Works seamlessly in Playwright without needing custom JavaScript unless the DOM is deeply nested or dynamically built.
Suggested Posts:
1. Handle Alerts in Playwright
2. BrowserContext in Playwright
3. Handle Dropdowns in Playwright
4. Handle IFrames in Playwright
5. Page Object Model in Playwright