Finding elements
How a block finds the element it works on — CSS, XPath, frames and shadow roots — and how to pick one.
Blocks that act on the page find their element with a selector, written in the shared panel at the top of the block. A selector that starts with /, (, @ or id( is read as XPath. Anything else is read as CSS. There is no separate switch.
Beside Element Selector are two buttons. The crosshair, Select an element, opens the picker in the page of the profile chosen in the editor's toolbar. That profile's browser must already be open on the right page. Verify selector highlights what the selector matches there, or says Element not found.
In the picker, hover the element and click it. The Element Selector panel lists candidate selectors, ranked by how stable they are, with how many elements each matches. Tick Only unique selector to hide those that match more than one. Parent element and Child element move the choice up or down the page's structure. You can also type into its Selector box to test a selector. Press Select Element to put the selector into the block.
The picker's tools help with hard cases. Freeze (Alt+Shift+F) holds the page still, so you can pick a menu, tooltip or toast that disappears on its own. Relative describes an element by another one near it, as below. Scan finds shadow roots so you can pick what is inside them. The eye icon hides the panel, and the cross closes the picker.
Relative is for an element nothing about itself tells apart from its neighbours, such as a cell in a row that looks like every other row. Press Relative, then click the Target, the element you need a selector for. Then click an Anchor, something near it that is easy to recognise, such as the row's label or a heading. Two rows, Target and Anchor, appear above the field, and the list shows the selectors of whichever row is lit.
Until you press Done, either half can be changed: click its row, then choose another selector from the list, type one, click another element on the page, or widen it with Parent element. Clicked them the wrong way round? ⇄ Swap exchanges the two roles, and each element keeps the selector chosen for it. Done writes one selector that starts at the anchor and reaches the target, and lists every form that found exactly that element, up to six, labelled by the relationship, such as Relative · Following sibling · CSS.
CSS can only look down and forward from the anchor. When the target is before the anchor or above it, the result is XPath. Swapping a pair can therefore turn a CSS answer into an XPath one. Relative picking works on the page itself: a click inside an iframe or a shadow root is refused with a message.
An element inside an iframe is written as the frame's selector, |>, then the element's selector inside that frame. Add one more |> per nested frame. The picker writes these for you. Blocks after a Switch frame block already work inside that frame.
An element inside a shadow root is written as the host's selector, >>>, then a CSS selector inside it. Repeat >>> for a shadow root inside another. Only open shadow roots can be entered this way.
Pick what identifies the element and will not change: an id that is not generated, then test attributes such as data-testid, then name, aria-label or placeholder, then the tag and its type. Avoid generated class names such as css-1x3kfp2, layout classes such as mt-2, long chains of div > div, and positions like nth-child(3). When an element is known by its words, use XPath with normalize-space(). Text that changes with the site's language only suits a workflow for one language.
Tick Wait for selector on anything that appears after a page load or a click. A correct selector used too early fails the same way as a wrong one.
WarpX Phone's blocks find elements on the phone's screen, not in a page, so CSS, frames and shadow roots do not apply. A phone block's Selector takes a locator picked with Inspect, which opens the phone's Inspector; an XPath over the screen's elements, such as //android.widget.TextView[@text='Log in'], using attributes like resource-id, text and content-desc; or plain text, the element with exactly that text. Verify looks for it on the phone now.
- Element Selector
The CSS or XPath selector of the element. It accepts references such as
{{variables.buttonSelector}}.Examplebutton[data-testid="checkout"]- Multiple
Acts on every element the selector matches instead of the first one only. A block that reads the page then returns a list.
ExampleUnchecked- Mark element
Skips elements this block already handled, so each pass of a loop takes the next one, such as a Click element on
.inbox-rowopening the next unopened row. Only offered for CSS selectors. The block tags each element it handles with the attributeblock--plus its id, so the tags are gone once the page reloads or changes.ExampleUnchecked- Wait for selector
Waits for the element to appear before the block acts, instead of failing at once.
ExampleChecked- Selector timeout (ms)when Wait for selector is ticked
How long to wait for the element, in milliseconds. The block fails if it has not appeared by then.
Example10000
| You write | It means |
|---|---|
#login-email | The element with id login-email. |
button[data-testid="checkout"] | The button marked for testing as checkout. Test attributes survive redesigns. |
form[action*="/search"] input[name="q"] | The q field of the search form, scoped to the form it belongs to. |
input[aria-label="Search"] | The field whose accessible label is Search. |
//button[normalize-space()="Sign in"] | The button whose text reads Sign in, spaces tidied. |
//label[normalize-space()="Email"]/following::input[1] | The first field after the label Email, for a field with nothing of its own to go by. |
//td[normalize-space()="Order #1042"]/following-sibling::td[3] | What Relative writes for the third cell after the one reading Order #1042: the anchor, then the way to the target. |
ul.results > li | Every result row, with Multiple ticked. |
iframe[src^="https://pay.example.com/"] |> button[type="submit"] | The submit button inside the payment iframe. |
checkout-widget >>> button.pay | The pay button inside the shadow root of checkout-widget. |