📣 Requestly API Client – Free Forever & Open Source. A powerful alternative to Postman. Try now ->

How to Handle Dynamic Elements in Selenium: A Complete Guide

Rohit Rajpal
Learn how to handle dynamic elements in Selenium using XPath, CSS selectors, waits, and best practices to build stable, reliable test automation.
How to Handle Dynamic Elements in Selenium A Complete Guide

Dynamic elements are one of the biggest causes of instability in Selenium test automation. These are elements on a web page that change their attributes, location, or visibility across different sessions or interactions.

When locators point to values that shift at runtime, tests often fail even though the application works as intended. Handling such elements requires strategies that can adapt to changing identifiers, delayed rendering, and dynamic page structures.

This article explains the different types of dynamic elements and explains how they behave in modern applications.

What are Dynamic Elements in Selenium

In Selenium, a dynamic element is any web element whose attributes or position in the Document Object Model (DOM) change from one page load to another or after a user action. Unlike static elements, which can be located by a fixed ID or class, dynamic elements often require flexible strategies to identify them.

The main challenge is that dynamic elements do not stay the same between sessions. A locator that worked during script creation may no longer work when the test runs again. This leads to failed test executions and wasted time fixing broken locators.

Some common cases of dynamic elements include:

  • Changing IDs: Many frameworks generate element IDs dynamically, often appending session numbers or random values. For example, an element might have id=”input-4521″ on one load and id=”input-7398″ on another.
  • Dynamic class attributes: CSS classes that reflect state changes such as “active,” “selected,” or “highlighted” are often attached or removed dynamically.
  • Dynamic lists or tables: Search results, dropdowns, and data grids where elements are inserted or re-ordered depending on query or backend response.
  • Dynamic text content: Labels or values that update based on user input or API calls.
  • Asynchronous rendering: Elements that appear only after AJAX calls, lazy loading, or JavaScript execution.

Why Handling Dynamic Elements is Important for Test Automation

Dynamic elements are one of the leading reasons Selenium scripts fail during execution. If dynamic elements are not handled properly, the impact shows up in several ways:

  • Unreliable test results: Tests may pass once and fail the next time without any actual application defect. This makes it difficult to trust automation outcomes.
  • High maintenance effort: Teams spend more time updating locators than writing new tests, which slows down automation adoption.
  • False negatives: A test might fail because of a broken locator rather than an issue with the application, leading to wasted debugging effort.
  • Blocked regression cycles: Large test suites cannot be executed with confidence if locators are fragile, delaying feedback on releases.
  • Team inefficiency: Developers and testers spend cycles fixing scripts instead of improving coverage or validating new features.

How Dynamic Elements Behave in Web Applications

Dynamic elements are not just “difficult locators.” Their behavior comes from how modern applications build and update the DOM. Instead of loading a fixed HTML page, most web applications rely on JavaScript frameworks and asynchronous requests that constantly modify elements after the initial page load.

Here are the main ways dynamic elements behave:

  • Generated at runtime: IDs, names, and classes are often created dynamically by the frontend framework or backend service. For example, a button might receive id=”login_9832″ during one session and id=”login_1276″ in another. Selenium scripts that rely on a fixed ID will fail because the attribute value is not constant.
  • Replaced or re-rendered: Frameworks like React or Angular frequently destroy and recreate DOM nodes when updating state. To the human eye, the element looks unchanged, but in the DOM it is a completely new node. Selenium sees the old reference as “stale” and throws a StaleElementReferenceException.
  • Loaded asynchronously: Elements may not exist at the time Selenium looks for them. AJAX calls or lazy loading delay the appearance of certain components. For example, a search result grid may only populate after the backend responds, so Selenium must wait before interacting with it.
  • Visibility toggling: Some elements exist in the DOM but are hidden until a specific action is taken. Dropdown menus, modals, and accordions are examples. Selenium can find the element, but cannot interact with it until it is visible or clickable.
  • Dynamic positioning: Lists, tables, and carousels often shift element positions when new data arrives or when filters are applied. A button that was the third element in one run may be the fifth in another, breaking index-based locators.

Types of Dynamic Elements in Selenium

Dynamic elements fall into several categories, each with distinct behaviors and testing challenges. Understanding these categories helps in selecting the right handling technique in Selenium.

1. Dynamic IDs

Dynamic IDs are one of the most common issues. Many frameworks generate element IDs at runtime by appending random numbers or session identifiers. For example, a text field might be id=”username_5421″ in one session and id=”username_8762″ in the next. To a tester, the field looks the same, but to Selenium the locator no longer matches.

The problem with dynamic IDs is that they break static locators. Scripts that rely on full ID matches will fail, even though the element exists. This leads to repeated maintenance as IDs change with every run.

2. Dynamic Classes

Class attributes are often tied to the state of an element. A navigation link may have the class “active” when selected and lose it when another link is clicked. Error fields may gain a class like “invalid” only after validation. These changes are intentional and reflect user interaction, but they create unstable locators if the test depends only on class values.

Since class names can switch quickly, a locator that worked in one test step may fail in the next. This makes class-based selectors unreliable unless combined with other attributes.

3. Dynamic Lists and Tables

Lists, dropdowns, and tables are frequently populated from backend data. The order and number of elements can change depending on filters, queries, or sorting. For example, the first row in a table during one test run might not be the same row in the next.

If locators are built only on indexes such as “select the second row” they often interact with the wrong element. This leads to inconsistent validation, especially in regression suites where data changes frequently.

4. Dynamic Text Content

Dynamic elements are sometimes defined by their text values. Welcome messages, product prices, and search results can all change based on context. For example, a label might display “Welcome, John” in one run and “Welcome, Sarah” in another.

Locators that rely on exact text matching will fail whenever the text changes. Even partial matches can become unreliable if the application inserts additional text, such as promotional banners or contextual tooltips.

5. Asynchronously Loaded Elements

Modern applications rely heavily on AJAX and lazy loading. Elements may not exist in the DOM at the moment Selenium tries to interact with them. For instance, an infinite scroll page only loads the next set of items when the user reaches the bottom.

In such cases, Selenium throws a “NoSuchElementException” because it looked for the element too early. Timing is the main challenge here, and without synchronization, tests fail even though the functionality works.

6. Re-rendered DOM Elements

Some frameworks like React and Angular re-render parts of the DOM whenever the application state changes. Instead of modifying the existing node, they destroy it and create a new one in its place. To Selenium, the old node reference is invalid, leading to a StaleElementReferenceException.

This behavior can confuse testers because the element looks unchanged on screen. In reality, Selenium needs to locate the element again after the re-render to continue interaction.

How to Handle Dynamic Elements in Selenium

Dynamic elements require flexible locator strategies and synchronization techniques. Selenium provides several ways to interact with them reliably. Each method addresses a specific type of dynamic behavior.

1. Relative XPath

When attributes such as IDs or names keep changing, Relative XPath is one of the most reliable ways to locate elements. Instead of matching the full attribute, you can use XPath functions to target only the stable part.

For example, if the login button has IDs like login_1234 or login_8742, the stable prefix “login” can be used:

				
					//button[contains(@id, 'login')]
				
			

Relative XPath can also locate elements based on their relationship with nearby nodes. For instance, you can select the label next to a specific input field:

				
					//label[text()='Username']/following-sibling::input
				
			

This makes XPath useful when attributes are unstable but the structure around the element is consistent.

2. CSS Selectors for Dynamic Elements

CSS selectors are faster than XPath and often easier to read. They allow partial attribute matching using special operators.

If a button’s ID starts with “submit” but ends with random digits, you can write:

				
					button[id^='submit']
				
			
  • ^= matches elements where the attribute starts with a value.
  • $= matches elements where the attribute ends with a value.
  • *= matches elements where the attribute contains a value.

CSS selectors also allow chaining multiple conditions, which helps when you want to identify elements by both class and attribute.

3. Using Explicit Waits

When elements load asynchronously, the issue is timing rather than unstable attributes. Selenium provides explicit waits that pause execution until a condition is met.

Example using WebDriverWait in Java:

				
					WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
WebElement element = wait.until(
    ExpectedConditions.visibilityOfElementLocated(By.id("dynamicElement"))
);
				
			

Explicit waits solve problems where Selenium attempts to interact with an element before it exists or becomes visible. They are essential for applications that use AJAX, infinite scrolling, or delayed rendering.

4. Handling Dynamic IDs with Patterns

Some applications generate IDs that change but still follow a predictable pattern. In such cases, you can avoid hardcoding the entire ID and instead capture the stable prefix or suffix.

For example, an ID like user_1452 or user_8931 can be matched as:

				
					//input[starts-with(@id,'user_')]
				
			

This approach reduces maintenance effort because you no longer need to update locators every time the numeric part changes.

5. Using JavaScript Executor

In certain cases, Selenium locators fail because elements are hidden, covered by overlays, or re-rendered in unusual ways. When standard locators cannot interact with the element, JavaScript Executor provides direct access to the DOM.

Example:

				
					JavascriptExecutor js = (JavascriptExecutor) driver;
js.executeScript("document.getElementById('dynamicId').click();");
				
			

While powerful, this method should be a last resort. Overusing JavaScript Executor bypasses Selenium’s built-in checks, which can hide real issues like element invisibility or incorrect state.

Challenges and Debugging for Dynamic Elements in Selenium

Even with locator strategies and waits in place, dynamic elements can still cause problems during execution. These challenges usually show up as runtime exceptions or inconsistent test behavior. Knowing how to debug them saves time and prevents unnecessary locator changes.

1. Stale Element Reference

A common error in applications that re-render components is StaleElementReferenceException. This happens when Selenium stores a reference to an element, but the application replaces that element with a new one during a state update.

Example: You find a table cell, apply a filter, and then try to read the same cell again. The DOM has been refreshed, so the old reference is no longer valid.

Always re-locate the element after any action that could refresh the DOM. Do not store element references across multiple operations if the page is expected to change.

2. Element Not Found

Sometimes Selenium cannot find an element even though it appears visible to the user. This often occurs with asynchronous rendering. Selenium looks for the element too early, before AJAX calls complete or lazy-loaded components appear.

Use explicit waits with conditions like visibilityOfElementLocated or presenceOfElementLocated. Inspect the DOM at runtime to confirm whether the element is loaded later than expected.

3. Element Not Clickable

In some cases, Selenium identifies the element but cannot interact with it. This usually happens when the element is covered by another layer, such as a loading spinner, modal, or tooltip.
Scroll the element into view using Actions or JavascriptExecutor. Check for overlays in the DOM that might block clicks. Use waits to ensure the interfering element disappears before interacting.

4. Multiple Matching Elements

Dynamic lists and tables sometimes create multiple elements with similar attributes. Selenium may pick the first match, which may not be the intended one.

Make locators more specific by combining attributes, using parent-child relationships, or narrowing down based on visible text. Avoid using generic locators like //button without context.

5. Conditional Visibility

Some elements exist in the DOM but are hidden until triggered. Selenium may find the element but fail to perform an action if it is not visible or enabled.

Confirm the element’s visibility using explicit waits. Check style attributes such as display: none or visibility: hidden during inspection. Trigger the necessary action (like clicking a dropdown) before interacting with the element.

Running Selenium Tests on Real Devices

Dynamic elements are not guaranteed to behave the same way across environments. A locator that works in one browser or device may fail in another because of differences in rendering, layout, or timing.

Here are some reasons to run Selenium tests on real devices.

  • Browser rendering differences: Each browser engine interprets DOM updates in its own way. Chrome may expose an element immediately while Safari delays rendering the same element. Without cross-browser testing, these differences remain hidden.
  • Mobile viewport adjustments: Responsive design changes how elements are placed on the page. A button visible in the desktop view may be collapsed under a menu on a mobile device. Index-based or position-dependent locators often fail in these cases.
  • Performance variations: Devices with different processing power load content at different speeds. A dynamic element may appear instantly on a powerful desktop but only after several seconds on a mid-range phone. Tests need waits that adapt to these differences.
  • Touch vs click interactions: Some elements react differently to touch events compared to mouse clicks. Hover menus or drag-and-drop components are common examples. Validating only on desktop misses these mobile-specific behaviors.
  • Cross-platform consistency: Locators that work across multiple browsers and devices are more reliable long term. Real-device testing confirms that handling strategies for dynamic elements hold up in varied conditions.

BrowserStack gives teams instant access to a wide range of real browsers and devices without the need for in-house infrastructure. Selenium tests can be executed on 3,500+ real devices and browsers, covering desktop and mobile environments. This ensures that locator strategies for dynamic elements are validated under real-world conditions.

With BrowserStack, testers can:

  • Run parallel Selenium tests across multiple browsers and operating systems to speed up coverage.
  • Validate how dynamic elements behave on real iOS and Android devices without setting up physical labs.
  • Catch environment-specific locator failures early by testing on the same browsers and devices used by end users.

Conclusion

Dynamic elements break Selenium tests when attributes change, elements are re-rendered, or content loads asynchronously. Static locators cannot handle these conditions, so strategies like XPath functions, CSS selectors, explicit waits, and pattern-based ID handling are necessary.

BrowserStack enables this by providing instant access to thousands of real devices and browsers without the need for in-house infrastructure.

Written by
Rohit Rajpal
Rohit Rajpal is a B2B Content Strategist at BrowserStack, helping SaaS brands build AI-first strategies that drive authority and revenue. He writes about content, strategy, and the future of search in the zero-click era.

Related posts