Selecting the right element is a foundational part of reliable web automation. Wrk provides two generations of selection capabilities, a legacy CSS-based approach and a modern locator-based model built around a flexible Element identifier.
As web applications become more dynamic and interactive, element selection needs to be expressive, resilient, and easy to reason about. Wrk’s Element identifier is designed to meet those needs while remaining approachable for anyone familiar with the basics of web automation.
Advanced
The Advanced Selection Method in Wrk's Web automation introduces locators(based on Playwright's Locators), a richer interpretation of the Element identifier.
Instead of being limited to CSS, an Element identifier can now be a composed selector string that combines different selector types into a single expression.
This makes it possible to describe elements based on what they are, what they contain, and where they appear, rather than relying only on DOM structure.
Supported Selector Types
Wrk Element identifiers support multiple selector engines, each suited to different situations.
CSS selectors
CSS selectors remain fully supported and are commonly used for structural scoping.
div.modal
# Find a div that has the class modal
button.primary
# Find a button that has the class primary
They are especially useful for narrowing the search to a specific section of the page.
XPath selectors
XPath is supported for more complex relationships that are difficult to express in CSS.
//section[@id="pricing"]
# Find the section of the page that is the pricing section.
xpath=.//button[contains(., "Buy")]
# Find any button that has the word ‘Buy’ in it.
Relative XPath expressions work well when combined with other selectors.
Semantic and Engine-Based Selectors
Wrk supports multiple selector engines, each designed for a specific way of identifying elements. These engines can be used on their own or combined together in a single Element identifier.
Selector engine overview
Selector engine | What it selects by | Example | When to use it |
| Page structure and attributes |
| Scoping to sections or containers |
| Structural relationships |
| Complex relationships not expressible in CSS |
| Accessibility role and name |
| Interactive elements like buttons and dialogs |
| Visible text content |
| Selecting elements by what the user sees |
| ID attribute |
| Selecting elements by its |
| Stable automation attributes |
| Elements with dedicated automation IDs |
| Input placeholder text |
| Inputs with meaningful placeholders |
| Alternative text |
| Images and icons |
| Title attribute |
| Tooltips or icon-only controls |
| href attribute |
| Buttons or links with a known URL |
How these engines work together
Each selector engine focuses on a different aspect of the page. When combined using >>, they form a clear, step-by-step description of how to find an element.
Example:
css=div.modal >> role=button[name="Close"]
This can be read as:
Find the modal container, then within it find the Close button.
It represents a left-to-right resolution process:
Find elements matching the first selector
Search within those elements using the next selector
Continue until the final selector is resolved
Each part of the identifier further narrows the scope, making complex selections easier to understand. Note this can be done by mixing multiple selector engines together like in the example above. This allows each step to use the selector type that best fits the situation.
You also refine a selector for a given element by using attributes or filters on a single selector:
role=button[name="Submit"]
css=button:has-text("Submit")
You can expand the sections below to see more details and examples of filters for each Selector engine:
css
css
Supported filters
Tag name
Classes and IDs
Attribute selectors
Pseudo-classes
Structural selectors
Examples
css=button.primary
css=input[type="email"]
css=button:has-text("Submit")
xpath
xpath
Supported filters
Attributes
Text (exact or partial)
Hierarchy
Position
Logical conditions
Examples
xpath=//button[contains(text(),"Submit")]
xpath=//input[@type="email" and @required]
role
role
Available Roles
Available Roles
"alert" | "alertdialog" | "application" | "article" | "banner" | "blockquote" | "button" | "caption" | "cell" | "checkbox" | "code" | "columnheader" | "combobox" | "complementary" | "contentinfo" | "definition" | "deletion" | "dialog" | "directory" | "document" | "emphasis" | "feed" | "figure" | "form" | "generic" | "grid" | "gridcell" | "group" | "heading" | "img" | "insertion" | "link" | "list" | "listbox" | "listitem" | "log" | "main" | "marquee" | "math" | "meter" | "menu" | "menubar" | "menuitem" | "menuitemcheckbox" | "menuitemradio" | "navigation" | "none" | "note" | "option" | "paragraph" | "presentation" | "progressbar" | "radio" | "radiogroup" | "region" | "row" | "rowgroup" | "rowheader" | "scrollbar" | "search" | "searchbox" | "separator" | "slider" | "spinbutton" | "status" | "strong" | "subscript" | "superscript" | "switch" | "tab" | "table" | "tablist" | "tabpanel" | "term" | "textbox" | "time" | "timer" | "toolbar" | "tooltip" | "tree" | "treegrid" | "treeitem"
Supported filters
namecheckeddisabledexpandedpressedselectedlevel(headings)
Examples
role=button[name="Submit"]
role=checkbox[checked=true]
Regex support(Name only)
role=button[name=/submit|save/i]
role=heading[name=/pricing/i]
text
text
Supported filters
Exact or partial text
Examples
text=Welcome text="Sign in"
Regex support
text=/welcome/i text=/sign\s*in/i
id
id
Supported filters
ID attribute (exact or partial)
Examples
id=submit_btn
Regex support
label=/submit/i
data-testid
data-testid
Supported filters
Explicit automation ID
Examples
[data-testid="login-btn"] exact match
[data-testid^="login"] starts with
[data-testid$="btn"] ends with
[data-testid*="log"] contains
placeholder
placeholder
Supported filters
Placeholder text
Examples
[placeholder="Email address"] exact match
[placeholder^="Email"] starts with
[placeholder$="address"] ends with
[placeholder*="Email"] contains
alt
alt
Supported filters
Alt text
Examples
[alt="Company logo"] exact match
[alt^="Company"] starts with
[alt$="logo"] ends with
[alt*="Company"] contains
title
title
Supported filters
Title value
Examples
[title="Close button"] exact match
[title^="Close"] starts with
[title$="button"] ends with
[title*="Close"] contains
href
href
Supported filters
href value
Examples
[href="/account/login"] exact match
[href^="/account"] starts with
[href$="?ref=dashboard"] ends with
[href*="/orders/"] contains
Why this matters
Using the right selector engine makes Element identifiers:
Easier to read and understand
More resilient to layout and styling changes
Better aligned with how users interact with the page
Automation becomes clearer when selectors describe what an element is, not just where it happens to be.
Why This Approach Works Well for Automation
Compared to CSS-only selection, locator-based Element identifiers provide:
Clear expression of intent
Better resilience to UI changes
Easier composition and reuse
A single string representation that is easy to inspect and troubleshoot
This makes automations easier to maintain as applications evolve.
Legacy
Wrk’s original selection system supports standard CSS selectors only.
In this mode, the Element identifier is interpreted strictly as a CSS selector.
Examples of legacy Element identifiers:
.login-form button.submit
ul.menu > li.active a
Strengths of the legacy approach
Familiar and widely understood syntax
Simple and predictable behavior
Works well for basic structural selection
Limitations
While CSS selectors are powerful, they can be limiting in automation scenarios:
They describe page structure rather than meaning
Small layout or markup changes can break automations
Selecting by visible text or purpose is difficult
Long selectors can become hard to read and maintain
These challenges become more noticeable as automations grow in size or need to survive UI changes.
Choosing the Right Selection Method
The Advanced Selection Method, locator-based Element identifier, is the recommended starting point for Web Automation. It provides greater flexibility, clearer intent, and better long-term maintainability, even for simple scenarios. The Legacy Selector is available to ensure backwards compatibility but should not be used in new automation builds.
