Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

To click a submenu reliably, first activate its parent the way the page expects—usually by hovering or clicking—then wait for the submenu item to become visible and enabled, and only then click it. Use a stable locator and reacquire the item after any page redraw. A fixed sleep or a successful element lookup alone does not establish that a click will work.

Identify how the menu opens

Before choosing a Selenium action, determine how the site reveals the submenu. Some menus open when a pointer enters a parent link; others open only after a button is clicked. A submenu may also be rendered only after activation. Inspect the page’s rendered DOM and observe the menu in a real browser rather than assuming that finding a child locator means it is ready to use.

Hover-revealed menus

For a hover menu, move the pointer onto its parent with ActionChains. The child may already exist in the DOM while hidden, or the page may create it only after the hover. In either case, wait for the child’s interactive state after moving the pointer. Selenium’s Python documentation demonstrates using ActionChains.move_to_element(parent).perform() for this kind of pointer interaction: Selenium Python documentation.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Click-expanded menus

If the parent is a button or disclosure control, click it instead of trying to hover. Then wait for the submenu item. If the markup exposes state such as aria-expanded, you can wait for that state as evidence the menu opened, followed by a wait for the target item itself. The exact attribute and locator depend on the page’s markup.

Use explicit waits instead of guessed delays

An element can be present but hidden, disabled, covered, or not yet attached to the current page after a redraw. Use a WebDriverWait condition that matches the next action. Selenium describes explicit waits as polling until a condition becomes true, and warns that fixed sleeps can be either too short or unnecessarily long: Selenium waiting strategies.

Hover and click a submenu item

The following pattern is for a page whose rendered markup has a parent with id products and a submenu link matching the supplied CSS selector. Replace those selectors with stable attributes from your application; keep the sequence of hover, wait, and click.

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

# Selenium Manager can obtain a compatible driver for supported setups.
driver = webdriver.Chrome()
wait = WebDriverWait(driver, 10)

try:
    driver.get("https://example.com")

    parent = wait.until(
        EC.visibility_of_element_located((By.CSS_SELECTOR, "#products"))
    )
    ActionChains(driver).move_to_element(parent).perform()

    reports = wait.until(
        EC.element_to_be_clickable(
            (By.CSS_SELECTOR, "#products-menu a[data-testid='reports']")
        )
    )
    reports.click()
finally:
    driver.quit()

This is a complete browser-session pattern, but the example selectors are illustrative: the target page must actually contain matching elements, and the URL must be the page you intend to test. The wait timeout is a maximum polling period, not a fixed pause; choose a timeout that fits the application and test environment.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Click a parent that expands the menu

For a click-expanded menu, wait until the parent control can be clicked, activate it, and then wait for the child. The locators below illustrate semantic attributes; adapt them to the site’s actual accessible markup.

parent = wait.until(
    EC.element_to_be_clickable(
        (By.CSS_SELECTOR, "button[aria-haspopup='true']")
    )
)
parent.click()

submenu_item = wait.until(
    EC.element_to_be_clickable(
        (By.CSS_SELECTOR, "[role='menu'] a[role='menuitem']")
    )
)
submenu_item.click()

Do not use a broad menu-item selector if the page has several menus. Scope the locator to the menu that was just opened, or add a stable attribute that identifies the intended child. Otherwise Selenium may click a different matching item elsewhere on the page.

Choose a locator and wait condition that match the page

Prefer stable, specific selectors

Prefer an id, a dedicated test attribute such as data-testid, or a meaningful accessible attribute when the application provides one. A positional XPath that selects “the second link” is fragile: inserting or reordering a menu item can silently change which destination it selects. Scope child locators to their parent menu when possible.

Know what “clickable” checks

Selenium’s element_to_be_clickable checks that an element is visible and enabled; it does not establish that an overlay, animation, or application event handler will accept the click. The API describes it as an expectation that an element is “visible and enabled such that you can click it”: Selenium Python expected conditions. If the menu has an explicit open state, wait for that state as well as the child’s visibility or clickability. If a transition covers the link, wait for the covering state to clear rather than adding an arbitrary delay.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Use visibility when you need to inspect, clickability when you need to click

A visibility wait is useful to confirm that a submenu has appeared before inspecting it or taking another action. A clickability wait is a better final condition before calling click() because it also checks that the element is enabled. Neither condition guarantees that the click will succeed if something else intercepts it, so investigate the rendered page when a click still fails.

Handle menus that redraw after activation

Modern pages may replace a menu node when it opens, updates, or navigates. A WebElement found before that replacement points to the old node and can become stale. Locate the child after activating the parent instead of holding on to an element captured before the menu changed.

locator = (By.CSS_SELECTOR, "#products-menu a[data-testid='reports']")
reports = wait.until(EC.element_to_be_clickable(locator))
reports.click()

If a click is supposed to trigger a redraw before a later interaction, wait for the old element to become stale and then find the replacement using the same stable locator:

old_element = driver.find_element(
    By.CSS_SELECTOR, "#products-menu a[data-testid='reports']"
)
old_element.click()

wait.until(EC.staleness_of(old_element))
replacement = wait.until(
    EC.element_to_be_clickable(
        (By.CSS_SELECTOR, "#products-menu a[data-testid='reports']")
    )
)

Use staleness_of only when the interaction is expected to remove or replace that particular node. If the node remains in place, waiting for staleness will time out; wait for the page’s actual changed state instead. Selenium documents stale-element and redraw-aware expected conditions in its API reference: Java ExpectedConditions API.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Diagnose common submenu failures

The exception often points to the layer of the interaction that failed. Check the current frame, rendered DOM, menu state, and overlays before changing the click method.

Symptom or exception What it usually means What to check or change
NoSuchElementException The locator did not match an element in the current context. The child may not exist until activation, may be in an iframe, or the selector may not match the rendered page. Activate the parent first if needed; inspect the rendered DOM and selector; switch to the correct frame before locating the child.
ElementNotInteractableException The node exists but is hidden, disabled, or otherwise not ready for interaction. Wait for visibility and enabled state after opening the menu. Confirm that the locator identifies the visible child rather than a hidden duplicate.
ElementClickInterceptedException Another element, such as an overlay or an in-progress animation, is covering the target click point. Wait for the covering state to clear, make sure the target is in view, and check whether the pointer opened the intended menu.
StaleElementReferenceException The page replaced the node after Selenium found it. Discard the old WebElement and reacquire the child after the redraw. Use a stale-element wait when replacement is expected.
The submenu closes before the click The pointer left the hover-sensitive region, perhaps while moving between the parent and child. Move onto the correct parent, wait for the child immediately, and avoid a pointer path that crosses a gap. Some menus require keeping the pointer over a bridge area between parent and submenu.

Do not mask an interaction problem with JavaScript

Calling a DOM click through JavaScript may bypass the real pointer path that a user or browser interaction test is meant to exercise. It can hide an overlay, focus, or event-sequencing issue rather than fix it. For a user-facing menu test, first make the expected hover or click, wait for the page’s real state, and use Selenium’s normal element click. If the site intentionally requires a different interaction, make that requirement explicit in the test.

Check context boundaries: frames and shadow DOM

Iframe menus

An element inside an iframe is not located from the top-level document. Switch into the correct frame before locating the parent or submenu; once inside it, use the same activation and wait sequence. Switch back to the default content before working elsewhere on the page. A correct selector evaluated in the wrong frame still produces a missing-element failure.

Shadow DOM menus

A submenu inside a shadow root may not be reachable with an ordinary document-level CSS selector. Use the component’s supported shadow-root access strategy to reach the relevant elements, then apply the same principles: activate the parent, wait for the child’s visible and enabled state, and reacquire after replacement. Do not treat iframe switching and shadow-root access as interchangeable; they are different DOM boundaries.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Avoid conflicting wait strategies

Keep synchronization explicit and tied to page state. Selenium warns, “Do not mix implicit and explicit waits,” because combined timeout behavior can be unpredictable: Selenium waiting strategies. If your test uses explicit waits, avoid adding an implicit wait casually. A long implicit wait can make an explicit wait take longer than its apparent timeout when each poll performs element lookups.

When a fixed delay is justified

A fixed delay is rarely a good substitute for waiting on a condition: network speed and animation timing vary between runs. If a page has a transition with no observable state and the test must allow it to finish, use the shortest delay that is genuinely required, then still verify the target’s state before clicking. Prefer an application-visible condition whenever one is available.

Or skip the browser setup

If your goal is to capture the page after it loads rather than test the pointer interaction itself, a screenshot API can return an image without you setting up a local browser session. It cannot perform this Selenium submenu click, verify menu behavior, or replace an interaction test. For that screenshot-only use case, ScreenshotNeo is a website screenshot API and MCP server. Its capture options include accepting cookie/consent banners and removing more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each of those steps can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, and responses identify page verdict and billing status in headers. Its MCP server provides screenshot tools for AI agents, and the free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000. See the ScreenshotNeo documentation for API parameters.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

To use the API, replace YOUR_API_KEY with your access key and replace the target URL with the page to capture. Sign up for 1,000 free screenshots a month with no card.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Frequently Asked Questions

Why can Selenium find a submenu link that a user cannot see?

Element lookup and visibility are separate: a hidden menu item can already be present in the DOM. Activate the parent and wait for the submenu to become visible before trying to interact with it.

Should I use a longer WebDriverWait when the submenu click is intercepted?

Not automatically. A longer wait helps only if the blocking state will eventually clear. Inspect the overlay, animation, pointer position, and menu state to identify what is preventing the click.

Can a screenshot API validate that Selenium clicked the right submenu item?

A screenshot can show the rendered result, but a screenshot API does not perform or verify Selenium’s pointer interaction. Use browser automation for the click and any assertion about its outcome.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.