When accessing Shadow DOM there are two main principles:
- Find the shadow root element
- Using the shadow root as a driver to interact with elements inside
it.
First Method
Please note - Since Selenium v4.5 the only supported locator is
CSS-Selector
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
# Wait for the shadow root wrapper element to be present
shadow_root_wrapper = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.CSS_SELECTOR, "#quick-task-container > cclqt-remove-background"))
)
# Get the shadow root
shadow_root = shadow_root_wrapper.shadow_root
# Wait for the image upload area element to be visible within the shadow root
image_upload_area = WebDriverWait(shadow_root, 10).until(
EC.visibility_of_element_located((By.CSS_SELECTOR, "sp-theme > cclqt-workspace > cclqt-image-upload"))
)
# Get the inner shadow root
inner_shadow_root = image_upload_area.shadow_root
# Send an image to the input field
inner_shadow_root.find_element(By.CSS_SELECTOR, "#file-input").send_keys("path_to_image\\file.png")
Second Method
Another approach is to utilize the execute_script()
method to execute JavaScript code to interact with the Shadow DOM:
# You should wait for element for smooth execution
shadow_root_script = "return document.querySelector('#quick-task-container > cclqt-remove-background').shadowRoot"
shadow_root = driver.execute_script(shadow_root_script)
image_upload_area = shadow_root.find_element(By.CSS_SELECTOR,"sp-theme > cclqt-workspace > cclqt-image-upload")
inner_shadow_root = image_upload_area.shadow_root
inner_shadow_root.find_element(By.CSS_SELECTOR, "#file-input").send_keys("path_to_image\\file.png")
When handling a complex DOM which envolved many nested Shadow DOMs the best way to find your element path is using the devtools: right click on the element > Copy > Copy js path
(example for Chrome)