Next-Gen App & Browser Testing Cloud
Trusted by 2 Mn+ QAs & Devs to accelerate their release cycles

The Shadow DOM (Document Object Model) is a web standard that encapsulates styles, markup, and behavior within a scoped and isolated DOM subtree. In this tutorial, you will learn various approaches and techniques to handle elements within the Shadow DOM using Cypress effectively.

Kailash Pathak
January 13, 2026
The concept of componentization has revolutionized website development, completely transforming how they are built. At the heart of this revolutionary shift is the introduction of Shadow DOM, a key component in this paradigm change. With Shadow DOM’s powerful method, developers can isolate styles, scripts, and markup within specific components. This encapsulation is a barrier, effectively shielding these components from the broader scope and avoiding accidental interference. The introduction of Shadow DOM marks a significant advancement in web development practices.
Developers may design modular and isolated components using Shadow DOM, guaranteeing their independence from the global scope. In addition to improving security, this separation makes maintenance easier and enables developers to concentrate on specific components without worrying about other variables interfering with their operation.
When it comes to automating elements within the Shadow DOM, it can be quite challenging compared to elements in the regular DOM. However, Cypress provides a solution for automating elements under the Shadow DOM.
In this blog, we will explore the complication of automating Shadow DOM in Cypress, a powerful end-to-end testing framework.
The Shadow DOM isolates component styles, scripts, and markup to prevent conflicts with the global document, offering modularity and improved maintainability. However, automating tests for Shadow DOM elements in Cypress is tricky, as they are hidden from the regular DOM, requiring special handling.
Why Handle Shadow DOM in Cypress?
To interact with Shadow DOM elements in Cypress, you can use the .shadow() command or configure the includeShadowDom flag in the Cypress settings. These methods ensure seamless automation and compatibility with encapsulated components, enhancing the reliability and accuracy of your tests.
How Can You Access Shadow DOM Elements in Cypress?
.shadow() method in Cypress allows you to interact with elements inside a Shadow DOM.includeShadowDom flag in the Cypress config file can be used to enable Shadow DOM element interactions globally or per command.The Document Object Model (DOM) is fundamentally a programming interface that web developers are given access to by browsers. It displays the document’s structure as a tree of objects, each representing a different aspect of the document, such as its components, attributes, and textual content. When it comes to web pages, developers can dynamically interact with them, altering their appearance and functionality in real-time. This is made possible by the hierarchical structure of web pages.
DOM serves as a fundamental interface for programs to dynamically manipulate the structure, style, and content of documents on the web. It empowers developers to create, read, update, and delete elements and attributes within a web page, enabling interactivity and dynamism. This dynamic capability of the DOM is crucial for crafting interactive web applications. By harnessing programming languages such as JavaScript, developers can access and modify the DOM, allowing them to build responsive and interactive web applications with unparalleled flexibility and power.

In the DOM, every branch within the tree structure leads to a node, which is a fundamental unit. These nodes are pivotal elements in the DOM, encapsulating various objects and data.
Each node represents a distinct document part, such as elements, attributes, and text content. This hierarchical arrangement allows web browsers to interpret and manipulate pages, enabling dynamic content and interactive user experiences.
Let us take an example of an HTML page. In this example, the HTML document contains a head section with a title element, setting the page title to “A simple web page”. The body section contains a heading element (< h1 >) with the text “Hello TestMu AI” and a paragraph element (< p >) with the text “How are you TestMu AI”. This HTML code would display a webpage with the specified content when rendered in a web browser.
<html lang=“en”>
<head>
<title>A simple web page</title>
</head>
<body>
<h1>Hello LambdaTest</h1>
<p>How are you LambdaTest</p>
</body>
</html>
As mentioned above, a logical tree of this HTML structure would look like this.

Shadow DOM stands for Shadow Document Object Model. It’s a web standard that offers a scoped subtree within a document, meaning that the DOM elements inside a Shadow DOM are hidden from the main document (& vice-versa). This encapsulation helps developers create widgets (or other components) with encapsulated styles and behaviors without worrying about conflicts with the styles or scripts of the main document (or other components).
It is particularly useful in web development when developers have to create isolated components with their styles and behavior, preventing conflicts with the styles and scripts of the main document or other components on the same page.
Shadow DOM enables the creation of multiple shadow trees alongside the standard document tree, representing the DOM structure of the entire project. Each tree possesses a root node, known as the shadow root, housing its unique elements and styling. These trees are linked to specific elements within the parent document tree or other shadow trees, with these connecting nodes referred to as shadow hosts. The demarcation line separating the regular DOM and the Shadow DOM is termed the shadow boundary.

Here are some of the key components of Shadow DOM:
Shadow DOM offers several benefits in web development. Here are some key benefits:
Let’s explore an example that demonstrates the process of attaching Shadow DOM to HTML and how it helps encapsulate the structure and styles of HTML.
Consider a simple example where you want to create a custom button component encapsulated within Shadow DOM:
In this example, we define a custom button component (< my-button >) that encapsulates its HTML structure and styles using Shadow DOM. The button’s appearance and behavior are isolated from the rest of the page, making it a self-contained component that can be used without interfering with the global CSS or JavaScript.
<!DOCTYPE html>
<html>
<head>
<title>Shadow DOM Example</title>
</head>
<body>
<my-button></my-button>
</body>
</html>
<script>
// Create a new custom element using the CustomElements API
class MyButton extends HTMLElement {
constructor() {
super();
// Create a Shadow DOM
const shadow = this.attachShadow({ mode: 'open' });
// Create a button element inside the Shadow DOM
const button = document.createElement('button');
button.textContent = 'Hi 👋 Click On Me';
// Add some styles to the Shadow DOM
const style = document.createElement('style');
style.textContent = `
button {
background-color: blue;
color: white;
padding: 10px 20px;
border: none;
cursor: pointer;
}
`;
// Attach the button and style to the Shadow DOM
shadow.appendChild(style);
shadow.appendChild(button);
}
}
// Define the custom element
customElements.define('my-button', MyButton);
</script>
Here’s a breakdown of the code:
Output:
The ‘Hi 👋 Click On Me’ button is inside the Shadow DOM.

Before delving into how to handle Shadow DOM elements using Cypress, it’s crucial to understand how to access these elements. The upcoming explanation will illuminate these challenges and solutions for effective Shadow DOM element handling in Cypress.
Before discussing how we can handle Shadow DOM in Cypress, we must discuss what will happen if a user tries to access Shadow DOM elements without using the method that is provided by Cypress to handle these elements.
Let’s examine the consequences of attempting to directly access Shadow DOM in Cypress, with detailed examples below.
Use Case 1
Let’s take an example of the TestMu AI Playground, where we have to enter data in the Name and Email field.
Let’s inspect the fields Name and Email. The screenshot below shows the Name and Email fields inside the shadow DOM.
Let’s write Cypress code to enter data in the Name and Email text field and execute the code locally.
it('Enter data in Field Name and Email', () => {
cy.visit('https://www.lambdatest.com/selenium-playground/shadow-dom')
cy.get('[type="text"]').find('input[placeholder="Name"]').type('LambdaTest')
cy.get('[type="text"]').find('input[placeholder="Email"]').type('[email protected]'})
})
Upon running the code, the error "Expected to find element: #input, but never found it. Queried from:" appears in the command log below. The error occurs because the fields are within Shadow DOM.


Use Case 2
Let’s take another example of the TestMu AI Playground, where we enter data in Sign Up Form fields inside the shadow DOM.
Let’s inspect the field. In the screenshot below, you can see that the Username and other fields are inside the shadow DOM

Let’s write Cypress code to enter data in the Username, Email, Password, and Confirm Password text fields.
it("Enter data in Fields Which are Inside the Shadow DOM ", () => {
cy.visit("https://www.lambdatest.com/selenium-playground/shadow-dom");
cy.get('[name="username"]').type("LambdaTest", { force: true });
cy.get('[name="email"]').type("[email protected]", { force: true });
cy.get('[name="password"]').type("LambdaTest123", { force: true });
cy.get('[name="confirm_password"]').type("LambdaTest123", { force: true });
});
Let’s run the above code. The screenshot below shows that the error displays Timed out retrying after 4000ms: Expected to find element: [name=”username”], but never found it. The reason is that fields are inside the Shadow DOM.

Before explaining how we can solve the above issue, it’s mandatory to understand the method we can use to access Shadow DOM elements.
Below is the syntax to access the Shadow element. Let’s see the methods that are used in accessing the element that is inside the Shadow DOM with detail example
Syntax:
.shadow(selector)
.shadow(selector, options)
Example:
Cypress provides a way to traverse into the Shadow DOM of an element for testing purposes. To interact with elements inside the Shadow DOM in Cypress, you can use the .shadow() command.
Assuming you have an element with an ID of ‘my-element’ inside a Shadow DOM:
<my-element>
#shadow-root (open)
<div class="content">Hi LambdaTest Content inside shadow DOM</div>
</my-element>
To traverse into the Shadow DOM and interact with the element with class content, you can use the .shadow() command in your Cypress test.
In this example, cy.get(‘my-element’).shadow() is used to traverse into the Shadow DOM of the my-element and find the element with class content inside the Shadow DOM in Cypress.
// Your Cypress test
it('should interact with an element inside shadow DOM', () => {
// Visit your webpage
cy.visit('http://your-app-url');
// Find the host element with ID "my-element"
cy.get('my-element').shadow().find('.content').should('have.text', 'Hi LambdaTest Content inside shadow DOM');
// Perform interactions or assertions on the element inside the shadow DOM
// For example, click the element inside the shadow DOM
cy.get('my-element').shadow().find('.content').click();
});
In the next section, you will see how we can handle the elements inside Shadow DOM in Cypress using the above-mentioned methods.
So far, you have seen an issue accessing the elements under the Shadow DOM. In Cypress, there are various methods to access Shadow DOM elements. The upcoming section will elaborate on these methods, providing a comprehensive understanding of how to interact with Shadow DOM elements effectively.
Below, you will see different ways to handle Shadow DOM in Cypress.
Let’s take the same example and use the shadow() command to enter data in the Name and Email field.
describe("Enter data in Fields Inside Shadow DOM Using shadow() method ", () => {
beforeEach(() => {
cy.visit("https://www.lambdatest.com/selenium-playground/shadow-dom");
});
it("Enter data in all Fields", () => {
cy.get("shadow-signup-form").shadow().find('input[name="username"]').type("Kailash", { for,ce: true });
cy.get("shadow-signup-form").shadow().find('input[name="email"]').type("[email protected]", { force: true });
cy.get("shadow-signup-form").shadow().find('input[name="password"]').type("lambdatest@123");
cy.get("shadow-signup-form").shadow().find('input[name="confirm_password"]').type("lambdatest@123");
});
});
Code Walkthrough
Here’s what each part does:
describe(“Enter data in Fields Inside Shadow DOM Using shadow() method”, () => { … });:
This sets up a test suite with a description.
describe("Enter data in Fields Inside Shadow DOM Using shadow() method ", () =>
beforeEach(() => { … });:
This is a hook that runs before each test case in the suite. In this case, it visits the specified web page before executing every test.
beforeEach(() => {
cy.visit("https://www.lambdatest.com/selenium-playground/shadow-dom");
});
it(“Enter data in all Fields”, () => { … });:
This is an individual test case with the description “Enter data in all Fields”. The test case is responsible for interacting with the elements inside the Shadow DOM and entering data into the specified fields.
it("Enter data in all Fields", () => {}
cy.get(“shadow-signup-form”).shadow();:
This line uses the cy.get() command to locate the Shadow DOM element with the tag name “shadow-signup-form”.
cy.get("shadow-signup-form").shadow().find();
.shadow().find(‘input[name=”username”]’);:
The .shadow() method is used to interact with elements inside the Shadow DOM, and find(‘input[name=”username”]’) is used to find the input field with the name “username”.
cy.get("shadow-signup-form").shadow().find('input[name="username"]');
.type(“Kailash”, { force: true });:
The .type() command is then used to simulate typing “Kailash” into this input field.
.type("Kailash", { force: true });
Similar lines follow for other input fields like Email, Password, and Confirm Password, where data is entered using the .type() command.
To access the input box within the Shadow DOM, we have used the .shadow() method. Once inside the shadow DOM, we can interact with the input box and enter the data in the ‘Username’, ’Email’, ‘Password’, and ‘Confirm Password’ fields.

The second approach handles the Shadow DOM in Cypress by adding the flag ‘includeShadowDom’ in the configuration file.
Add the flag in the ‘cypress.config.js’ file. In the config file, you can add “includeShadowDom“: true.
The includeShadowDom: true configuration option in Cypress enables interaction with elements inside Shadow DOM. When you set includeShadowDom: true in your Cypress configuration, Cypress will enable support for Shadow DOM and allow you to interact with elements inside Shadow DOM using commands like cy.get() and cy.find().
const { defineConfig } = require("cypress");
module.exports = defineConfig({
"includeShadowDom": true,
e2e: {
setupNodeEvents(on, config) {
},
},
});
Let’s write the code. Here, we are not using the .shadow() command.
describe("Enter data in Fields Inside Shadow DOM By enabling Flag “includeShadowDom”: true, ", () => {
beforeEach(() => {
cy.visit("https://www.lambdatest.com/selenium-playground/shadow-dom");
});
it("Enter data in Fields Which are Inside the Shadow DOM ", () => {
cy.visit("https://www.lambdatest.com/selenium-playground/shadow-dom");
cy.get('[name="username"]').type("LambdaTest", { force: true });
cy.get('[name="email"]').eq(0).type("[email protected]", { force: true });
cy.get('[name="password"]').type("LambdaTest123", { force: true });
cy.get('[name="confirm_password"]').type("LambdaTest123", { force: true });
});
});
The third approach is to handle the Shadow DOM in Cypress by adding the ‘includeShadowDom’ flag within specific commands.
In the third approach, instead of setting the ‘includeShadowDom’ flag globally, a more flexible approach is to include it within specific commands. This allows for finer control, enabling us to specify whether to include Shadow DOM per command.
describe("Enter data in Fields Inside Shadow DOM By adding Flag in commands “includeShadowDom”: true, ", () => {
beforeEach(() => {
cy.visit("https://www.lambdatest.com/selenium-playground/shadow-dom");
});
it("Enter data in Fields Which are Inside the Shadow DOM ", () => {
cy.get("shadow-signup-form").find('input[name="username"]',{ includeShadowDom: true }).type("Kailash", { force: true });
cy.get("shadow-signup-form").find('input[name="email"]',{ includeShadowDom: true }).type("[email protected]", { force: true });
cy.get("shadow-signup-form").find('input[name="password"]',{ includeShadowDom: true }).type("lambdatest@123");
cy.get("shadow-signup-form").find('input[name="confirm_password"]',{ includeShadowDom: true }).type("lambdatest@123");
});
});
Note: Automate Shadow DOM in Cypress on cloud. Try TestMu AI Today!
Handling Shadow DOM in Cypress on the cloud is crucial for comprehensive and accurate testing of modern web applications. The increasing trend of web applications utilizing Shadow DOM for encapsulating styles and functionality necessitates robust testing mechanisms.
As cloud testing environments like TestMu AI gain prominence, it becomes imperative to validate that the infrastructure supports the intricacies of Shadow DOM testing. This ensures that applications leveraging Shadow DOM can be thoroughly tested in cloud-based environments, guaranteeing the reliability and functionality of the application in real-world scenarios.
TestMu AI is an AI-based test execution and orchestration platform that offers over 3000 real browsers and operating systems to help you automate Shadow DOM in Cypress on the cloud. You can accelerate your Cypress testing with Java and reduce test execution time by multiple folds by running parallel tests on Cypress Cloud across multiple browsers and OS configurations.
Subscribe to the TestMu AI YouTube Channel and stay updated with the latest tutorials around automated testing, Cypress E2E testing, and more.
As we will execute the test cases on the TestMu AI platform, we must configure our tests for the TestMu AI cloud grid.
Prerequisite:
Step 1: Install the CLI
The command-line interface of TestMu AI enables us to execute your Cypress tests on TestMu AI. Use the Cypress CLI command via npm as shown below
npm install -g lambdatest-cypress-cli
Step 2: Generate lambdatest-config.json
Under the root folder, configure the browsers we want to run the tests. Use the init command to generate a sample lambdatest-config.json file or create one from scratch. Use the below command
lambdatest-cypress init
In the generated lambdatest-config.json file, pass the information below. Fill in the required values in the section lambdatest_auth, browsers, and run_settings to run your tests.
In the file below, we pass three browsers (Chrome, Firefox, and Electron) and run the test case in two browsers simultaneously.
{
"lambdatest_auth": {
"username": "Enter username",
"access_key": "enter access key"
},
"browsers": [
{
"browser": "Chrome",
"platform": "Windows 10",
"versions": [
"latest-1"
]
},
{
"browser": "Firefox",
"platform": "Windows 10",
"versions": [
"latest-1"
]
}
],
"run_settings": {
"build_name": "Cypress With Shadow DOM Example ",
"parallels": 2,
"specs": "./cypress/e2e/shadowDom/*.cy.js",
"ignore_files": "",
"feature_file_suppport": false,
"network": true,
"headless": false,
"reporter_config_file": "",
"npm_dependencies": {
"cypress": "13.3.0"
}
},
"tunnel_settings": {
"tunnel": false,
"tunnel_name": null
}
}

Run the below command to execute the test case on the TestMu AI.
lambdatest-cypress run --sync=true
As we run the above command, test execution starts, and test cases are run in parallel on the TestMu AI platform.
Test case execution
As we execute the test cases in the screenshot below, both test cases start executing in browsers (Chrome, Firefox) parallelly, and we can see the detailed report in the TestMu AI dashboard.
TestMu AI Dashboard offers users a convenient and intuitive interface to oversee test results, review test outcomes, and utilize various platform features. It enables live interactive testing, offering users a real-time view of the website or web application they are testing on a specific browser and operating system.
The screenshot below shows the test case starts executing in browsers (Chrome, Firefox).

The screenshot below shows that test cases are passed in the browser (Chrome, Firefox).

Here is the console log of executed test cases in the Chrome browser. You can see that three of the test cases are passing in TestMu AI Grid.

Here is the console log of executed test cases in the Firefox browser. You can see that three test cases passed on the TestMu AI Grid.

In this Cypress tutorial on handling Shadow DOM in Cypress, we’ve delved into the challenges of handling elements inside Shadow DOM, shedding light on the complexities of interacting with encapsulated components. We’ve explored various approaches and techniques to handle elements within the Shadow DOM effectively using Cypress.
Furthermore, we’ve discussed the integration of TestMu AI, an AI-powered test orchestration and execution platform, and how it enhances the capabilities of Cypress automation. By seamlessly running our Cypress tests across different browser versions and platforms, we ensure our applications’ compatibility and reliability in diverse environments. This integration empowers us to deliver high-quality web experiences to users across the digital landscape.
Did you find this page helpful?
More Related Hubs
TestMu AI forEnterprise
Get access to solutions built on Enterprise
grade security, privacy, & compliance