Skip to main content

Locator Patterns

Drama Finder uses sophisticated locator patterns to handle Vaadin’s shadow DOM structure and component composition. Understanding these patterns helps you work with complex components and create custom element wrappers.

Locator Delegation Pattern

Elements delegate to specific internal locators for different operations. This pattern ensures actions and assertions target the correct DOM element within a component’s shadow DOM.

Why Delegation Matters

Vaadin components often have a wrapper element and internal input elements. Different operations need to target different parts:

Focus Locator

The focus locator determines which element receives keyboard focus:
Input fields override this to focus the internal input:

Enabled Locator

The enabled locator determines where to check the disabled state:

ARIA Label Locator

The ARIA label locator specifies which element has the aria-label attribute:

Complete Example

Different component aspects (focus, enablement, aria-label) may target different internal elements. Locator delegation ensures each operation uses the correct target.

Component vs Input Locator

Understanding when to use the component locator versus the input locator is crucial:

Component Locator (getLocator)

Use for component-level attributes and state:

Input Locator (getInputLocator)

Use for input-specific operations:
Pitfall: Calling methods on the wrong locator (component root vs input).Solution: Use getInputLocator() for value/focus operations, getLocator() for component-level attributes.

Real-World Example

Shadow DOM Piercing

Playwright automatically pierces shadow DOM with CSS selectors, but XPath requires explicit handling.

CSS Selectors (Auto-Pierce)

XPath (Explicit Non-Pierce)

Prefer CSS selectors over XPath for Vaadin components. CSS selectors automatically pierce shadow DOM and are more readable.

Part Selectors

Vaadin components expose internal elements via part attributes for styling and testing:

Common Parts

Mixin Interfaces (Composition)

Shared behavior is extracted into interfaces with default implementations:
Elements implement mixins to inherit behavior:

Common Mixins

  • FocusableElement - Focus and blur operations
  • HasInputFieldElement - Value, label, helper text
  • HasValidationPropertiesElement - Validation state and messages
  • HasEnabledElement - Enabled/disabled state
  • HasClearButtonElement - Clear button interaction
  • HasPrefixElement - Prefix slot content
  • HasSuffixElement - Suffix slot content
  • HasThemeElement - Theme variant checking

Composite Element Pattern

Complex components compose simpler elements internally:

Using Composite Elements

Scoped Lookup Pattern

Factory methods support both page-level and scoped lookups:

Practical Scoping

Grid Cell Access Pattern

Grid uses a specialized pattern for accessing virtualized cells:

Grid Locator Delegation

Grid cells delegate to different locators:

Advanced Locator Chaining

Filter Options

And/Or Combinations

Creating Custom Elements

When creating custom element wrappers, follow these patterns:

1. Extend VaadinElement

2. Implement Relevant Mixins

3. Override Locator Delegation

4. Add Factory Methods

Best Practices

Prefer part selectors over complex CSS for accessing internal component elements:
Always use the appropriate locator for each operation:
Implement mixins to inherit common behavior instead of duplicating code:
Factory methods should always call .first() to avoid ambiguous matches:

Common Pitfalls

Pitfall: Using XPath selectors that don’t pierce shadow DOM.Solution: Use CSS selectors which automatically pierce shadow DOM.