Skip to content

How to Automate Shadow DOM in Selenium and Playwright

Practice shadow DOM automation — piercing open shadow roots, scoping to shadow hosts, nested shadow trees, forms inside shadow DOM, and evaluating closed shadow roots in Playwright, Selenium & Cypress.

Advanced20 min6 scenarios14 test cases

Interactive Scenarios

S01Scenario 1: Basic Shadow Host — Open Mode (Beginner)

Click the button rendered inside an open shadow root. Playwright auto-pierces — just chain locators.

[data-testid="shadow-host-basic"]shadow: open
Shadow button not clicked
S02Scenario 2: Multiple Shadow Hosts — Scope to Correct Host (Medium)

Three shadow hosts share data-testid="shadow-host". Scope to the correct one using data-host-id.

[data-host-id="host-1"]shadow: open
[data-host-id="host-2"]shadow: open
[data-host-id="host-3"]shadow: open
No host activated
S03Scenario 3: Nested Shadow DOM — 2 Levels (Medium)
documentouter shadow rootinner shadow root
[data-testid="shadow-outer-host"]shadow: open

Inner host has class="shadow-inner-host" and data-inner="true" but no testid. Playwright pierces both levels automatically.

Inner shadow not interacted
S04Scenario 4: Form Inside Shadow DOM — getByRole / getByLabel (Hard)HARD

Input and select have id and name but no data-testid. Use getByRole or getByLabel inside the shadow scope.

[data-testid="shadow-form-host"]shadow: open
Shadow form not submitted
S05Scenario 5: Dynamic Content in Shadow DOM (Hard)HARD

Content loads after ~1.5 s. The revealed button has aria-label="Trigger Shadow Action" but no testid. Spinner has role="status" only.

[data-testid="shadow-dynamic-host"]shadow: openloading…
Dynamic shadow content not loaded
S06Scenario 6: evaluate() to Pierce Shadow Root (Challenge)CHALLENGE

Input has only name="evalCode". The button has no attributes at all— just text "Execute". Standard locators cannot target these. Use page.evaluate().

Standard locators (getByTestId, getByRole, getByLabel) will NOT find elements with no stable attributes inside shadow DOM. You must use page.evaluate() or js.executeScript().
[data-testid="shadow-eval-host"]shadow: open
Evaluate not executed