Locators
Locators are Playwright-style selector handles that re-query the DOM on every action. Unlike Element, a Locator never goes stale — it stores the selector, not the DOM reference.
Create a Locator
Accessibility selectors also return Locators:
loc := page.GetByRole("button", bonk.WithName("Submit"))
loc := page.GetByLabel("Email")
loc := page.GetByText("Welcome")
Actions
All actions wait for the element to appear before acting:
loc.Click()
loc.Fill("hello@example.com")
loc.Type("query", bonk.WithDelay(50*time.Millisecond))
loc.Press("Enter")
Read Properties
text, err := loc.Text()
inner, err := loc.InnerText()
html, err := loc.HTML()
val, err := loc.Attribute("href")
visible, err := loc.IsVisible()
box, err := loc.BoundingBox()
Screenshot
Wait
Wait for the element to be attached to the DOM:
Count
Nth and First
Select a specific match by index:
Filter
Narrow matches by text content or sub-locator containment. All criteria are AND'd together.
HasText / HasNotText
rows := page.Locator("tr")
activeRows := rows.Filter(bonk.LocatorFilter{HasText: "Active"})
withoutDraft := rows.Filter(bonk.LocatorFilter{HasNotText: "Draft"})
Has / HasNot
Keep or exclude elements that contain a descendant matching a sub-locator:
cards := page.Locator(".card")
// only cards that contain an <h2>
withHeading := cards.Filter(bonk.LocatorFilter{
Has: page.Locator("h2"),
})
// cards without a .badge element
withoutBadge := cards.Filter(bonk.LocatorFilter{
HasNot: page.Locator(".badge"),
})
Sub-locators can be CSS or accessibility selectors:
// cards containing the text "Total"
cards.Filter(bonk.LocatorFilter{
Has: page.GetByText("Total"),
})
Combining criteria
// active cards with a heading
cards.Filter(bonk.LocatorFilter{
HasText: "Active",
Has: page.Locator("h2"),
})
Chaining filters
page.Locator(".card").
Filter(bonk.LocatorFilter{HasText: "Active"}).
Filter(bonk.LocatorFilter{Has: page.Locator(".price")})
And
Match elements that satisfy both locators (intersection):
loc := page.Locator(".highlight").And(page.Locator(".visible"))
// combine CSS with accessibility selectors
submitBtn := page.Locator("button").And(page.GetByText("Submit"))
Or
Match elements that satisfy either locator (union). Results are in document order:
alerts := page.Locator(".error").Or(page.Locator(".warning"))
count, _ := alerts.Count()
fmt.Printf("Found %d alerts\n", count)
Locator vs Element
| Locator | Element | |
|---|---|---|
| Stores | Selector or JS expression | DOM object ID |
| Goes stale | Never | Yes (auto-retries once) |
| Re-queries | Every action | Only on stale error |
| Created via | page.Locator(), page.GetByRole(), etc. |
page.Query(), page.WaitSelector() |
Use Locator when the DOM is dynamic and elements may be re-rendered. Use Element for performance when the DOM is stable.