Shadow DOM Selectors

What is Shadow DOM?

Shadow DOM is a web standard that provides encapsulation for JavaScript, CSS, and HTML. It allows hidden DOM trees to be attached to elements in the regular DOM tree, keeping the implementation details separate from the main document DOM.

Working with forms inside Shadow DOM requires special handling because:

Form with Shadow DOM Components

This form demonstrates elements encapsulated within Shadow DOM that require special selection strategies.

Register

Shadow DOM Selectors JSON Configuration

Copy this JSON configuration to test the form with TesterUtilities extension. It uses shadow DOM piercing selectors to access elements inside shadow roots.

{
  "url": "(https://pawel-albert.github.io/utilities-for-testing-extension/shadow-dom-form.html|file:///.*shadow-dom-form.html)",
  "formData": {
    "registrationForm": {
      "type": "form",
      "timeout": 5000,
      "fields": {
        "email": {
          "queryType": "shadowDOM",
          "selector": "custom-input[name='email'] input",
          "type": "input",
          "data": "test.user@example.com",
          "dataType": "static"
        },
        "password": {
          "queryType": "shadowDOM",
          "selector": "custom-input[name='password'] input",
          "type": "input",
          "data": "SecurePassword123!",
          "dataType": "static"
        },
        "fullName": {
          "queryType": "shadowDOM",
          "selector": "custom-input[name='fullName'] input",
          "type": "input",
          "data": "John Doe",
          "dataType": "static"
        },
        "country": {
          "queryType": "shadowDOM",
          "selector": "custom-select[name='country'] select",
          "type": "select",
          "data": "us",
          "dataType": "static"
        },
        "newsletter": {
          "queryType": "shadowDOM",
          "selector": "custom-checkbox[name='newsletter'] input",
          "type": "checkbox",
          "data": true,
          "dataType": "static"
        },
        "comments": {
          "queryType": "shadowDOM",
          "selector": "custom-textarea[name='comments'] textarea",
          "type": "textarea",
          "data": "This is a test comment using Shadow DOM selectors.",
          "dataType": "static"
        }
      },
      "submit": {
        "queryType": "shadowDOM",
        "selector": "custom-button button",
        "type": "click",
        "data": null,
        "dataType": null
      }
    }
  }
}

How Shadow DOM Selectors Work

In the TesterUtilities extension, shadow DOM selectors use a special algorithm to pierce through shadow boundaries and access elements within shadow roots.

// Example of how shadow DOM selectors work:
function queryShadowSelector(document, selector) {
  // Split the selector into parts (for nested shadow DOMs)
  const parts = selector.split(' > ');
  
  // Start with the document as the root
  let currentRoot = document;
  let element = null;
  
  // Traverse each part of the selector
  for (let i = 0; i < parts.length; i++) {
    const part = parts[i];
    
    // Find the element in the current root
    const elements = currentRoot.querySelectorAll(part);
    if (elements.length === 0) return null;
    
    element = elements[0];
    
    // If we're not at the last part and the element has a shadow root,
    // set the current root to the shadow root for the next iteration
    if (i < parts.length - 1 && element.shadowRoot) {
      currentRoot = element.shadowRoot;
    }
  }
  
  return element;
}

Custom Web Components Implementation

The custom web components used in this form are implemented as follows:

// Example of a custom input component:
class CustomInput extends HTMLElement {
  constructor() {
    super();
    const type = this.getAttribute('type') || 'text';
    const name = this.getAttribute('name');
    const required = this.hasAttribute('required');
    
    // Create shadow DOM
    this.attachShadow({ mode: 'open' });
    
    // Add content to shadow DOM
    this.shadowRoot.innerHTML = `
      
      
    `;
  }
}