In a browser test, a custom find step targets an element using the Locator field, which accepts CSS, XPath, and Playwright locator syntax as a single string. This article is a reference for the locator syntax mabl supports and how to write each type.
Browser tests only
Custom find steps are only supported in browser tests. To learn about targeting elements in a mobile app, see creating reliable find steps in mobile tests.
For a walkthrough of when and how to add a custom find step, see Create a custom find step. Before you reach for a locator, it's worth trying Configure Find first; it's easier to maintain and doesn't require knowledge of CSS, Playwright, or XPath query syntax.
Supported locator syntax
The Locator field accepts three syntaxes. CSS and XPath are standard selector languages, while Playwright syntax adds selector engines, such as text= and role=, along with techniques for combining and refining matches.
| Locator type | How to write it | Example |
|---|---|---|
| CSS | Enter the selector directly, with no prefix. | button.add-to-cart |
| XPath | Add an xpath= prefix. |
xpath=//button[@id='submit'] |
| Playwright | Use Playwright syntax, such as a text= or role= engine. |
text=Add to cart |
CSS
CSS selectors work in the Locator field without a prefix. For example, button.add-to-cart targets a button with the add-to-cart class.
CSS is often the best starting point. The syntax is quick to read, it's generally faster than XPath, and it can target elements inside a shadow DOM, which XPath can't reach.
XPath
To use an XPath expression, add an xpath= prefix so mabl knows to evaluate the string as XPath rather than CSS. For example, xpath=//button[@id='submit'] targets a button by its id.
Unlike CSS selectors, XPath expressions can traverse backward up the DOM, selecting a parent or ancestor from a child element. For example, if a table row has no stable attributes but one of its cells does, you can match the cell and climb to the row:
xpath=//td[text()='Widget A']/ancestor::tr
Reserve XPath for cases the other selectors can't express. Nested sibling and table traversal with XPath is expensive across most browsers, so it's slower than CSS as a general-purpose strategy.
Playwright locators
Playwright syntax adds two things on top of CSS and XPath: selector engines that match elements in new ways, and techniques for combining and refining matches. Because chaining and ordinal selection are Playwright syntax, using either one makes the whole locator a Playwright locator, even when the pieces you chain are CSS or XPath.
Text and role engines
text= and role= are Playwright engines. text= matches an element by its visible text, and role= matches by ARIA role, which are both useful when an element has no stable class or id.
text=Add to cart
role=button
Chaining
Use >> to chain locators together, narrowing the search from one locator to the next. mabl evaluates each locator in order and scopes the next one to the results of the previous one.
For example, the following locator finds the list item that contains the text "Product 2," then finds the "Add to cart" button within that item:
li:has-text("Product 2") >> button:has-text("Add to cart")
Writing Playwright chains as a string
The Playwright documentation mostly shows locators chained in code, such as page.getByRole('listitem').filter({ hasText: 'Product 2' }). Because the Locator field takes a single string value, you express that same chain with >> instead:
role=listitem >> text=Product 2
For the full syntax reference, see Playwright locators.
Ordinal selection
When several elements match the same locator, use nth to target one by its position. Append >> nth= followed by the index:
-
>> nth=0targets the first match. -
>> nth=-1targets the last match.
For example, .list-item >> nth=0 targets the first element with the list-item class. Negative indexes count from the end, so nth=-1 is a reliable way to target the last match even when the number of matching elements changes between runs.
Using variables in a locator
You can include mabl variable syntax in a locator to target elements with data-driven values. Reference a variable with the {{@varName}} format:
- CSS:
div.{{@sample_var}} - XPath:
xpath=//div[@class="{{@sample_var}}"]
When the step runs, mabl resolves the variable and evaluates the locator with the resolved value.