Shadow DOM

Back

Loading concept...

Shadow DOM Handling in Selenium 🕵️

The Secret Room Inside Your Web Page

Imagine your web page is a big house. Most rooms are easy to visit — you just open the door and walk in. But some websites have secret rooms with hidden doors. These secret rooms are called Shadow DOM.

Regular Selenium commands can’t find things inside these secret rooms. It’s like trying to grab a toy that’s locked in a box inside another box. You need a special key!


🏠 What is Shadow DOM?

Think of Shadow DOM like a snow globe. Inside the snow globe is a tiny world — trees, a house, snowflakes. But you can’t just reach in and touch the tree. The glass (the shadow boundary) keeps it separate.

Why do websites use Shadow DOM?

  • To keep their special components safe and private
  • To prevent outside styles from breaking their design
  • Popular in modern websites using Web Components
graph TD A["Regular DOM"] --> B["Shadow Host"] B --> C["Shadow Root"] C --> D["Hidden Elements"] C --> E["Secret Buttons"] C --> F["Private Text"] style C fill:#ff6b6b,color:#fff style D fill:#4ecdc4 style E fill:#4ecdc4 style F fill:#4ecdc4

🔑 The Magic Key: Shadow Root

To open the secret room, you need to find the Shadow Host (the door) and then get the Shadow Root (the key).

Regular Way (Doesn’t Work):

# This FAILS for Shadow DOM!
driver.find_element(By.CSS_SELECTOR,
    "button.hidden-button")

The Magic Key Way (Works!):

# Step 1: Find the door (shadow host)
host = driver.find_element(
    By.CSS_SELECTOR, "my-component")

# Step 2: Get the key (shadow root)
shadow = host.shadow_root

# Step 3: Enter and find your element!
button = shadow.find_element(
    By.CSS_SELECTOR, "button")

🎯 Real Example: Finding a Hidden Button

Let’s say there’s a website with a custom video player. The play button is hiding inside Shadow DOM.

The HTML looks like this:

<video-player id="player">
  #shadow-root (open)
    <div class="controls">
      <button class="play-btn">
        Play
      </button>
    </div>
</video-player>

Your Selenium Code:

# Find the shadow host
player = driver.find_element(
    By.ID, "player")

# Get inside the shadow root
shadow = player.shadow_root

# Now find the hidden button!
play_btn = shadow.find_element(
    By.CSS_SELECTOR, ".play-btn")

play_btn.click()  # It works!

🪆 Nested Shadow DOM (Boxes Inside Boxes!)

Sometimes there’s a secret room… inside another secret room! Like a Russian nesting doll (Matryoshka).

graph TD A["Main Page"] --> B["Outer Shadow Host"] B --> C["Outer Shadow Root"] C --> D["Inner Shadow Host"] D --> E["Inner Shadow Root"] E --> F["🎯 Target Element"] style C fill:#ff6b6b,color:#fff style E fill:#764ba2,color:#fff style F fill:#4ecdc4

How to reach the deepest element:

# First door
outer_host = driver.find_element(
    By.CSS_SELECTOR, "outer-component")
outer_shadow = outer_host.shadow_root

# Second door inside first room
inner_host = outer_shadow.find_element(
    By.CSS_SELECTOR, "inner-component")
inner_shadow = inner_host.shadow_root

# Finally! The treasure!
target = inner_shadow.find_element(
    By.CSS_SELECTOR, ".secret-element")

🛡️ Open vs Closed Shadow DOM

Open Shadow DOM = Unlocked door

  • You can use .shadow_root to get inside
  • Most common type

Closed Shadow DOM = Locked vault

  • .shadow_root returns None
  • Very rare, extra secure
# Checking if it's open or closed
host = driver.find_element(
    By.CSS_SELECTOR, "my-element")

shadow = host.shadow_root

if shadow is None:
    print("It's CLOSED! Cannot enter.")
else:
    print("It's OPEN! Let's explore!")

đź”§ JavaScript Backup Method

If .shadow_root doesn’t work, use JavaScript as a backup:

# Using JavaScript to get shadow root
shadow = driver.execute_script(
    "return arguments[0].shadowRoot",
    host_element)

# Now find elements inside
button = shadow.find_element(
    By.CSS_SELECTOR, "button")

🎮 Finding Multiple Elements

Just like regular Selenium, you can find many elements at once:

# Find the shadow host
host = driver.find_element(
    By.CSS_SELECTOR, "nav-menu")
shadow = host.shadow_root

# Get ALL menu items (returns a list)
items = shadow.find_elements(
    By.CSS_SELECTOR, ".menu-item")

# Click each one
for item in items:
    print(item.text)

⚡ Quick Tips for Shadow DOM

Situation Solution
Can’t find element Check if it’s in Shadow DOM
.shadow_root is None It might be closed shadow DOM
Nested components Chain multiple .shadow_root calls
Dynamic loading Add waits before accessing shadow root

🚀 Waiting for Shadow DOM Elements

Shadow elements might take time to load. Use waits!

from selenium.webdriver.support.ui import \
    WebDriverWait
from selenium.webdriver.support import \
    expected_conditions as EC

# Wait for host to appear
host = WebDriverWait(driver, 10).until(
    EC.presence_of_element_located(
        (By.CSS_SELECTOR, "my-component")))

# Get shadow root
shadow = host.shadow_root

# Wait for element inside shadow
element = WebDriverWait(shadow, 10).until(
    lambda s: s.find_element(
        By.CSS_SELECTOR, ".target"))

🌟 Complete Example: Real World Scenario

Let’s automate a modern website with Shadow DOM:

from selenium import webdriver
from selenium.webdriver.common.by import By
import time

# Start browser
driver = webdriver.Chrome()
driver.get("https://example-site.com")

# Step 1: Find the custom component
component = driver.find_element(
    By.CSS_SELECTOR, "custom-dropdown")

# Step 2: Access its shadow DOM
shadow = component.shadow_root

# Step 3: Click the dropdown trigger
trigger = shadow.find_element(
    By.CSS_SELECTOR, ".dropdown-trigger")
trigger.click()

# Step 4: Select an option
time.sleep(0.5)  # Wait for animation
option = shadow.find_element(
    By.CSS_SELECTOR,
    ".option[data-value='choice-1']")
option.click()

print("Selected successfully!")
driver.quit()

🎯 Remember This!

  1. Shadow DOM = Hidden Room - Regular selectors can’t see inside
  2. Shadow Host = The Door - Find this first
  3. Shadow Root = The Key - Use .shadow_root to enter
  4. Nested = Multiple Keys - Chain shadow roots for deep elements
  5. Open = Accessible - Most shadow DOMs are open
  6. Closed = Rare - Very few are locked (returns None)

🏆 You Did It!

Now you can handle Shadow DOM like a pro! Remember:

“Every secret room has a door. Every door has a key. .shadow_root is your key!”

Go explore those hidden elements! 🚀

Loading story...

Story - Premium Content

Please sign in to view this story and start learning.

Upgrade to Premium to unlock full access to all stories.

Stay Tuned!

Story is coming soon.

Story Preview

Story - Premium Content

Please sign in to view this concept and start learning.

Upgrade to Premium to unlock full access to all content.