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:
- Shadow DOM creates a boundary that regular DOM selectors cannot cross
- Shadow DOM elements are not directly accessible from the main document
- You need to traverse through shadow roots to access elements inside
Form with Shadow DOM Components
This form demonstrates elements encapsulated within Shadow DOM that require special selection strategies.
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 = `
`;
}
}