Handle ShadowDom in Playwright

  

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>



Website to automate: https://books-pwakit.appspot.com/














Java Code Example using Playwright:

Here, below are the steps we are performing in code.

(a) After creating page object, we are navigating to web application: https://books-pwakit.appspot.com/

(b) Then, we are creating locator object using page.locator, and "book-app" here is selector.

(c) then, we are accessing input box by id input.

(d) Then we are writing text in the text field as "Playwright"


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");
        }
    }
}


Important Points:
  • "#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

Handle Alerts in Playwright

 

Handling alert popups (JavaScript alerts, confirms, prompts) in Playwright Java involves listening for the Dialog event on the Page object. When a JavaScript alert, confirm, or prompt appears on a webpage, Playwright can catch it using a listener and either accept or dismiss it accordingly.








How Alerts Work in Playwright

  • Alerts are modal dialogs, meaning they block interaction with the page until dismissed.
  • Playwright automatically detects these dialogs and allows you to handle them.
  • When an alert appears, it triggers a dialog event on the page.


Types of JavaScript Dialogs

  • Alert → Only one button: OK
  • Confirm → Two buttons: OK and Cancel
  • Prompt → Input + OK/Cancel

How can we handle Alerts in Playwright:

There are three main things you can do with alerts in Playwright:

(a) Accept the alert: This is done by clicking OK on alert box. We can also provide input if its is prompt alert.

(b) Dismiss the alert: This is like clicking Cancel on a confirm or prompt.

(c) Get alert text: We can read the message displayed in the alert before accepting or dismissing it.















Concept

  • page.onDialog(handler) allows us to listen to dialog events.
  • Use dialog.accept() to accept it.
  • Use dialog.dismiss() to dismiss it.
  • Use dialog.accept("input") to send input to prompt dialogs.

Some key points related to Alerts
  • Alerts pause page execution, so you need to handle them before performing actions that trigger the alert.
  • Playwright allows listening for the dialog event, which ensures you can control the alert at the right moment.
  • Always handle alerts in synchronous flow with the actions that trigger them to avoid timeouts.

Handling Alert Popup in Playwright Java

Sample Website: https://the-internet.herokuapp.com/javascript_alerts








Code Example:

import com.microsoft.playwright.*;

public class HandleAlertPopup {
    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();

            // Set up dialog handler
            page.onDialog(dialog -> {
                System.out.println("Dialog message: " + dialog.message());
                dialog.accept();  
                // Accept the alert
                // dialog.dismiss(); // Use this for cancel
                // dialog.accept("Your input"); // For prompt dialog input
            });

            // Navigate to page with alert
            page.navigate("https://the-internet.herokuapp.com/javascript_alerts");

            // Click the button to trigger alert
            page.locator("text=Click for JS Alert").click();

            // Optional: Wait for result text
            String result = page.locator("#result").textContent();
            System.out.println("Result after handling alert: " + result);

            browser.close();
        }
    }
}


Code explanation:

(a) Setting up dialog handler and uses accept() for handling alerts.
(b) Navigate to the url by page.navigate()
(c) Click on 'Click for JS Alert button ' to generate alert message
(d) it got handled and captures text displayed on screen - 'You successfully clicked        an alert'
(e) Printed that alert result message.


Playwright Code responsible for handling alerts







Output:

Dialog message: I am a JS Alert
Result after handling alert: You successfully clicked an alert


Suggested Posts:

1. Playwright with TestNG Integration
2. BrowserContext in Playwright
3. Handle Dropdowns in Playwright
4. Handle IFrames in Playwright
5. Page Object Model in Playwright