ScreenshotNeo

BlogGuides

Selenium 4 Relative Locators: How to Find Web Elements

Learn how Selenium 4 relative locators find elements above, below, beside, or near a reference element, with runnable Python examples and troubleshooting.

By the ScreenshotNeo team4 October 20268 min read

Selenium 4 relative locators find an element by combining a normal locator with its position relative to a known element. Use above, below, to_left_of, to_right_of, or near when the target is hard to identify directly but its spatial relationship is clear. Selenium evaluates rendered element geometry using JavaScript getBoundingClientRect(); these locators therefore depend on the page layout at capture time. See Selenium’s locator guide.

1. What relative locators do

A relative locator has two parts: a candidate locator that describes the kind of element to find, and a spatial relationship to a reference element. For example, “the button below the email field” first narrows candidates to buttons, then uses the email field’s position to select one.

This is useful when the reference has a stable ID or other straightforward locator but the target does not. Relative locators are not inherently more reliable or faster than CSS or XPath. They express layout relationships, so choose them when that relationship is meaningful and remains clear at the viewport used by the test.

2. Python: runnable Selenium 4 example

Install Selenium with python -m pip install selenium. This example uses Selenium Manager, included with current Selenium, to obtain a compatible browser driver when needed. It assumes a reachable page has an input with ID email and a submit button below it; replace the example URL and locators with the page under test.

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.relative_locator import locate_with

options = webdriver.ChromeOptions()
# Uncomment to run without opening a browser window:
# options.add_argument("--headless=new")

driver = webdriver.Chrome(options=options)
try:
    driver.get("https://example.com/form")

    email = driver.find_element(By.ID, "email")
    submit = driver.find_element(
        locate_with(By.TAG_NAME, "button").below(email)
    )
    submit.click()
finally:
    driver.quit()

The reference can be passed as a WebElement, as above, or supplied as a locator. Python’s documented form is locate_with(By.CSS_SELECTOR, "p").above(element). Import locate_with from selenium.webdriver.support.relative_locator.

3. Relations, chaining, and ambiguity

Python method Meaning Example
above(reference) Candidate is above the reference locate_with(By.TAG_NAME, "input").above(label)
below(reference) Candidate is below the reference locate_with(By.TAG_NAME, "button").below(email)
to_left_of(reference) Candidate is left of the reference locate_with(By.TAG_NAME, "button").to_left_of(cancel)
to_right_of(reference) Candidate is right of the reference locate_with(By.TAG_NAME, "button").to_right_of(cancel)
near(reference) Candidate is within the near distance locate_with(By.TAG_NAME, "input").near(email)

Chain relationships when a single condition matches multiple candidates. For example, constrain a button to be below an email field and to the right of a cancel button:

from selenium.webdriver.support.relative_locator import locate_with

submit = driver.find_element(
    locate_with(By.TAG_NAME, "button")
    .below(email)
    .to_right_of(cancel)
)

The filters narrow the candidate set; they do not make an unclear page layout unambiguous by themselves. Prefer a unique candidate selector, and assert that the intended number of elements was found when the test depends on uniqueness.

How near works in Python

In the Python binding, near(reference) uses a default distance of 50 pixels. You can specify a positive distance in pixels, for example .near(email, 100). A distance less than or equal to zero is invalid. See the Python relative locator API reference. Use an explicit distance when the default does not fit the interface’s spacing, and avoid a broad radius that admits unrelated candidates.

4. Choosing a reference and candidate locator

  1. Choose a reference element that you can locate directly and that represents the right anchor, such as a labeled field or a known button.
  2. Choose a candidate locator narrow enough to describe the target type, such as a button, link, or input. A broad selector can leave several spatial matches.
  3. Apply the relation that describes the page at the test viewport. Add another relation if the first still matches multiple elements.
  4. Check that the result exists and is the intended element before interacting with it.
  5. Keep viewport, responsive breakpoint, and page state stable when the test relies on geometry.

If the target has a durable ID, accessible name, or semantic role that can be located directly, that direct locator may be clearer and less tied to layout. Relative locators are most helpful when spatial context is easier to state than a direct target locator.

5. Other Selenium language bindings

The concept and five relationships are available across Selenium bindings, but method names and syntax differ. Consult the official locator guide for binding-specific examples. These short forms illustrate the documented API shape; use the matching import/package setup and driver initialization for your project.

Java

import static org.openqa.selenium.support.locators.RelativeLocator.with;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;

WebElement email = driver.findElement(By.id("email"));
WebElement submit = driver.findElement(
    with(By.tagName("button")).below(email)
);

JavaScript

const { By, locateWith } = require('selenium-webdriver');

const email = await driver.findElement(By.id('email'));
const submit = await driver.findElement(locateWith(By.tagName('button')).below(email));

C#

using OpenQA.Selenium;
using OpenQA.Selenium.Support;

var email = driver.FindElement(By.Id("email"));
var submit = driver.FindElement(RelativeBy.WithLocator(By.TagName("button")).Below(email));

Ruby

email = driver.find_element(id: 'email')
submit = driver.find_element(
  relative(:tag_name, 'button').below(email)
)

Kotlin

import org.openqa.selenium.By
import org.openqa.selenium.support.locators.RelativeLocator.with

val email = driver.findElement(By.id("email"))
val submit = driver.findElement(with(By.tagName("button")).below(email))

6. Geometry, timing, and edge cases

  • Responsive layout: a candidate may move, stack, or reorder at another viewport. Set the window size explicitly when position is part of the test.
  • Dynamic content: wait for the reference and candidate layout to settle before locating. A locator evaluated before rendering or after a layout shift can return a different result or no result.
  • Overlapping elements: bounding rectangles describe geometry, not which element is visually on top or receives a click. A spatial match may still be obscured or non-interactable.
  • Hidden or zero-size elements: geometry-based reasoning may not match what a user sees. Prefer visible, rendered anchors and candidates, and verify visibility before interaction.
  • Frames and shadow DOM: switch into the correct frame first; locate elements in the relevant browsing context. Relative relationships do not replace frame or shadow-root traversal.
  • DOM order: “above” and “below” refer to rendered position, not source order. CSS positioning can make those differ.
  • Multiple matches: spatial relations can legitimately match several elements. Narrow the candidate locator or chain another relation, then assert the expected match.

7. Troubleshooting

Symptom Likely cause Fix
NoSuchElementException No candidate satisfies the selector and relation, or the page has not settled. Check the reference and candidate locator independently; wait for rendering; confirm the expected viewport and state.
Wrong element returned The candidate selector is broad or more than one element satisfies the relationship. Narrow the candidate selector and chain a second relation. Add an assertion for the expected element or count.
Python import error The import path is wrong or an old Selenium package is installed. Install/update the Selenium package and import locate_with from selenium.webdriver.support.relative_locator.
near rejects the distance The Python distance is zero or negative. Pass a positive pixel distance; omit it to use Python’s 50-pixel default.
Works at one screen size only The relationship changes after responsive reflow. Set the test viewport deliberately or use a direct semantic locator that is independent of position.
Element found but click fails The element is covered, disabled, outside the viewport, or otherwise not interactable. Check visibility and enabled state, wait for overlays to close, and scroll or use a more appropriate interaction.
Driver/session startup fails Browser installation, driver compatibility, or environment setup is missing. Use a supported installed browser and current Selenium; inspect the driver startup error and environment configuration.

8. Performance, reliability, and maintenance

Selenium’s documentation describes relative locators as using JavaScript getBoundingClientRect() to obtain element size and position. The cited sources provide no comparative performance measurements, so do not assume a relative locator is faster than CSS or XPath. In practice, its extra value is expressive: it can encode a spatial relationship when the target lacks a good direct identifier.

For maintainable tests, anchor to a stable reference, keep candidate selectors specific, make viewport and relevant page state explicit, and avoid relying on incidental pixel arrangements. If a layout redesign changes the relationship, the test may need updating; a stable semantic selector can be less layout-sensitive.

9. Capture a page to inspect its layout

When a visual layout is difficult to reason about, a screenshot can help you inspect the reference and neighboring elements at the same viewport used by a test. Selenium remains the tool that locates and interacts with the elements.

cURL

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

Python

import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://example.com/form"}, timeout=90)
open("shot.webp", "wb").write(r.content)

Node.js

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://example.com/form' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

See the ScreenshotNeo API documentation for request options. For inspecting a responsive layout, request the same viewport used by your browser test.

10. FAQ

Are relative locators part of Selenium 4?

Yes. Selenium calls them Relative Locators; they were previously called Friendly Locators.

Does above mean earlier in the HTML?

No. The relationship is based on rendered element geometry, not DOM order.

Can I use a locator instead of a WebElement as the reference?

Yes. The reference can be provided as a locator or as an already located element.

Is near always 50 pixels?

The Python binding documents a 50-pixel default. Its distance can be specified explicitly; other bindings may expose different syntax.

Or skip the browser setup

ScreenshotNeo captures a page with one API request. Cookie banners, popups, and chat widgets are removed before the shot; bot checks, blank pages, and failed loads are never billed. An MCP server lets AI agents take screenshots. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000.

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

Read the API docs and sign up for 1,000 free screenshots a month, no card required.