Search code examples
javascriptpuppeteershadow-domamp-stories

Manipulate / set style shadowRoot using Puppeteer


I try to take Screenshots of AMP Stories, without the sound and share buttons.

After I found out that there is something called shadow DOM I wonder how to set display : none there:

addStyleTag({content: '.i-amphtml-story-system-layer-buttons { display : none!important }'})

I think I made it to access the shadow DOM like this.

const shadowRootInnerHTML = await page.evaluate(() => {
    return document.querySelector("body > amp-story > div").shadowRoot.innerHTML
});

This is what I'm using currently,

const browser = await puppeteer.launch({
  slowMo: 250,
  args: [
    '--disable-infobars',
  ]
});
const page = await browser.newPage()

await page.emulate({
  name: 'iPhone1080x1920',
  userAgent: 'Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1',
  viewport: {
    width: 360,
    height: 640,
    deviceScaleFactor: 3,
    isLandscape: false
  }
});

await page.goto(urlToTest, {
  waitUntil: 'networkidle2',
  timeout: 0
});

const textContent = await page.evaluate(() => {
  return document.querySelector("body > amp-story > div").shadowRoot.innerHTML
});

Solution

  • Amp pages have multiple div elements inside amp-story.

    We can execute this vanilla JavaScript which will hide away the top slide and share button on amp pages.

    I have added two ways inside this code, you can apply either one.

    // there are multiple div elements inside amp-story
    const elements = [...document.querySelectorAll("body > amp-story > div")];
    
    elements.map(rootElement => {
      // find the shadowRoot inside if it exists
      const shadowRoot = rootElement.shadowRoot;
    
      if (shadowRoot) {
        /**
         * WAY 1: Find the element and apply css to it directly
         */
        // this holds the top share button and pagination slides
        const element = shadowRoot.querySelector(
          ".i-amphtml-story-system-layer"
        );
    
        // forcefully hide the element
        if (element) element.style.setProperty("display", "none", "important");
    
        /**
         * WAY 2: Append your own style to the <style> tag inside the amp shadowRoot
         */
        shadowRoot.querySelector('style').innerHTML += `.i-amphtml-story-system-layer { display : none!important }`
      }
    });
    

    Basically,

    • Find the div
    • Get the shadowRoot
    • Either find the element and apply directly, or add style to the tag.

    Result on a sample amp page:

    amp page without top bar