Configuring synchronization behavior
Web automation can be challenging due to dynamic page loading, asynchronous content, and varying page response times. Kolibrium provides a flexible synchronization mechanism that goes beyond simple visibility checks, allowing developers to define precise conditions for element readiness.
Kolibrium automatically ignores org.openqa.selenium.NoSuchElementException while waiting for elements to become ready, so waits don't fail on the first miss. Stale elements are also retried by re-locating the element during the wait.
Single elements: Defining readiness
By default, Kolibrium checks if an element is displayed using the WebElement's isDisplayed property.
val button by driver.id("submit-button") // Default behavior: checks if element is displayed
When working with web elements, simply checking if an element is displayed might not be sufficient. Kolibrium allows you to define complex readiness conditions using Kotlin's powerful lambda syntax.
Common practice is to wait until the element is displayed and enabled so it can be clicked.
In order to facilitate this waiting strategy, we can specify what WebElement properties should be evaluated to be true before performing an action on it.
This is done by providing a predicate that determines when the found element is considered ready for use.
val button by driver.id("button") { isDisplayed && isEnabled } // Wait until button is both visible and enabled
Or, by using Kolibrium's extension property on WebElement, it can be simplified to
val button by driver.id("button") { isClickable }
where isClickable is defined as
public val WebElement.isClickable: Boolean
get() = isDisplayed && isEnabled
If you are using IntelliJ IDEA or Aqua, and have enabled Inlay Hints (Settings -> Editor -> Inlay Hints -> Lambdas -> Kotlin -> Implicit receivers and parameters), you will see a this: WebElement hint after the opening brace.

This indicates that we have access to the WebElement, meaning we can use other properties as well, such as isSelected to determine when the element is ready for use.
In fact, you can write any code inside the braces as long as it evaluates to true.
If you don't want to perform any checks on a WebElement, use a readiness predicate of { true }, which treats the element as ready regardless of its state.
Advanced readiness conditions
The following locator definitions require all the listed conditions to be true before being considered "ready".
val searchInput by driver.id("search-input") {
isDisplayed &&
getAttribute("placeholder")?.isNotEmpty() == true &&
isEnabled
}
val dynamicElement by driver.id("dynamic-content") {
isDisplayed &&
getAttribute("class")?.contains("loading") == false &&
text.contains("Ready")
}
Multiple elements: Collective readiness
When working with collections of elements, Kolibrium provides flexible synchronization strategies.
Wait until all elements are visible
val links by driver.classNames("navigation-link") // Default: waits until the list is non-empty and all elements are displayed
Specific size validation
val productCards by driver.classNames(
value = "product",
) {
size == 9 // Wait until exactly 9 elements are present
}
Multi-element delegates always perform a fresh lookup and are not cached. You do not need to disable caching when waiting for dynamic lists; Kolibrium will keep polling until your readiness condition is met.
You can also use WebElements helper properties:
isDisplayed: all elements are visibleisEnabled: all elements are enabledisClickable: all elements are both displayed and enabled
Advanced collection conditions
val formInputs by driver.cssSelectors("form input") {
all { it.isEnabled && it.getAttribute("value")?.isNotEmpty() == true } // Ensure all inputs are enabled and have values
}
Synchronization strategies for collections
all { }: Every element must satisfy the condition.any { }: At least one element must satisfy the condition.count { }: Validates number of elements meeting a condition.