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)
document→outer shadow root→inner 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