Search code examples
javascriptjqueryfrontendweb-component

How to programmatically update an input inside shadow dom?


Fiddle: https://jsfiddle.net/5zrwdjy7/2/

I'm trying to automate keystrokes using a script inside Cypress, but the target website uses web components as inputs. The input elements are nested inside shadow dom therefor.

I am trying to trigger the input event as per a regular input as follows:

const input = document.querySelector('input')
input.value = 'new value'
input.dispatchEvent(new Event('input'))

Nothing happens, the value remains unchanged and there is no text displayed in the input. Is it possible to programmatically update input inside shadow dom?


Solution

  • Since the shadow encapsulates details of a component, it prevents regular traversal of the DOM. To access it:

    1. Find the web component available in the light DOM
    2. Traverse its shadow DOM:
    const lightComponent = document.querySelector('web-component')
    const shadowInput = lightComponent.shadowRoot.querySelector('input')
    shadowInput.value = 'shadow value'
    shadowInput.dispatchEvent(new Event('input'))
    

    Source: https://javascript.info/shadow-dom-events

    Example

    // Create shadow dom inside <input-container>
    customElements.define('input-container', class extends HTMLElement {
      connectedCallback() {
        const shadow = this.attachShadow({mode: 'open'});
        shadow.innerHTML = `<div><input type="text" /></div>`;
      }
    });
    
    // Programmatically update input value inside shadow DOM
    const lightComponent = document.querySelector('input-container')
    const shadowInput = lightComponent.shadowRoot.querySelector('input')
    shadowInput.value = 'Shadow value'
    shadowInput.dispatchEvent(new Event('input'))
    <body>
      <label>Input inside shadow DOM</label>
      <input-container></input-container>
    </body>