How to Pierce Shadow DOM with Playwright Locators

You normally do not need to do anything special to pierce open Shadow DOM in Playwright. Standard Playwright locators such as getByRole() can locate elements inside open shadow roots automatically.

await page
  .getByRole('button', { name: 'Add to cart' })
  .click();

Leapwork Play keeps this workflow even simpler for the test author: record the interaction in Play's browser and work with the generated Playwright test instead of manually traversing shadow roots or building custom DOM logic.

Try Leapwork Play →

How do you interact with Shadow DOM elements in Play?

The following example uses ServiceNow, where elements in the navigation UI are nested inside open shadow roots.

Browser DevTools shows the Shadow DOM structure:

sn-collapsible-list
    #shadow-root (open)
        ...

But the test author does not manually traverse that structure.

In Play, record the interaction with the element in the browser. The demo records actions such as:

  1. Click the Self-Service button to expand its menu in ServiceNow.

  2. Click the Incidents link in the ServiceNow navigation menu.

Play then runs those interactions against the application.

How does this work in Playwright?

Suppose the page contains:

product-card
  #shadow-root (open)
    button "Add to cart"

You can normally use:

await page
  .getByRole('button', {
    name: 'Add to cart'
  })
  .click();

You do not need to manually retrieve element.shadowRoot and then search inside it, that is the main answer for most Shadow DOM tests.

How Play simplifies the Shadow DOM workflow

With Playwright

With Leapwork Play

Write the locator for the target element

Record the interaction in Play's browser and generate the underlying Playwright

Playwright locators automatically pierce open shadow roots

Play builds on the same Playwright behavior in the generated test

Maintain the test code and locator

Work with the recorded interaction as a Play test step

Update locators when supported interactions change

Play's locator and self-healing workflow can help recover supported interactions

Play builds on Playwright's existing support for open Shadow DOM rather than introducing a separate traversal model. Play adds the recording, generated Playwright, and test workflow around those interactions.

Key exceptions

Keep these limits in mind:

  • XPath does not cross Shadow DOM boundaries. Use Playwright locators such as getByRole() instead.

  • Closed Shadow DOM is different. This guidance applies to open Shadow DOM; closed shadow roots intentionally restrict normal DOM access.

Best practices

  • Record the user interaction in Play rather than manually building Shadow DOM traversal logic when the Play workflow fits the test.

  • Use normal Playwright locators for elements inside open Shadow DOM.

  • Prefer user-facing roles, labels, and text over component-internal CSS.

  • Do not use XPath to cross a shadow-root boundary.

  • Distinguish open and closed Shadow DOM.

  • If several elements match, scope the locator by meaningful application context rather than DOM position.

Troubleshooting

Problem

What to do

Playwright cannot find an element inside a web component

Confirm that the component uses an open shadow root and check the locator itself.

XPath finds elements outside the component but not inside

XPath does not pierce the shadow root; use a normal Playwright locator.

Several elements inside components match

Scope the locator to meaningful surrounding content.

The component uses a closed shadow root

Do not assume the open-Shadow-DOM approach applies.

The interaction works manually but not in the test

Check the target locator and confirm the actual DOM boundary before adding custom traversal code.

Frequently asked questions

How does Leapwork Play handle Shadow DOM?

Play records interactions with ServiceNow elements nested inside open shadow roots and runs the resulting test without the author manually traversing those roots. This builds on Playwright's automatic handling of open Shadow DOM.

Does Playwright automatically pierce Shadow DOM?

Yes, standard Playwright locators can locate elements through open shadow roots without explicit shadowRoot traversal.

Do I need to call element.shadowRoot?

Usually not for open Shadow DOM. Start with a normal Playwright locator.

Does XPath pierce Shadow DOM?

No. Use a standard Playwright locator rather than XPath when the target is inside a shadow root.