Embed
Shadow DOM
The button below lives inside an open shadow root. Playwright pierces these by default.
Live widget · interact freely
Manual test goal
Pierce a shadow root, click a button rendered inside, and validate the encapsulated state.
Expected result
Playwright pierces shadow boundaries with default selectors; clicking the inner button increments a count.
Stable selectors
- Shadow host
[data-testid="shadow-host"] - Inner button
[data-testid="shadow-button"] - Inner counter
[data-testid="shadow-counter"]
Reference Playwright spec
shadow-dom.spec.ts
ts12345678910
import { test, expect } from '@playwright/test';
test('click element inside shadow root', async ({ page }) => {
await page.goto('https://lab.hakdogan.com/practice/shadow-dom');
// Playwright pierces open shadow roots automatically
await page.getByTestId('shadow-button').click();
await page.getByTestId('shadow-button').click();
await expect(page.getByTestId('shadow-counter')).toHaveText('count: 2');
});Demo Simulator
Simulated Playwright run · no real browser is launched
Idle
shadow-dom.spec.tshttps://lab.hakdogan.com/practice/shadow-dom
# console output will stream here