Nikhil Verma

XPaths in the modern age

This is a mirror of the original post on dev.to. For discussion and comments, please visit the original post.

XPaths are document query selectors for HTML and XML. They’re more powerful than CSS selectors and let you express complex queries.

Let me show you an example. Say you want to find the Google Search button by starting from a search input field. With XPaths you can do:

$x(`//textarea/ancestor::form//input[@value="Google Search"]`);

Try doing that with CSS selectors - you can’t traverse up the DOM like that.

Web Components and Shadow DOM

XPath is a pretty old specification (created in 1999 and last updated in 2016). It doesn’t support Shadow DOM.

The specification doesn’t account for Web Components which were invented way after XPath was created. This means XPath expressions cannot directly select elements within shadow DOM structures.

You have to first identify the component using XPath, then manually access its shadowRoot property to navigate deeper:

const host = $x(`//my-component`)[0];
const shadowElement = host.shadowRoot.querySelector(".element");

For nested components, this approach becomes unwieldy.

CSS selectors have the same limitation. The Lit library addresses this through custom @query decorators for element discovery.

Vue 3’s Text Node Problem

Vue 3 introduced a specific problem with XPath: it appends “anchor” nodes (empty text nodes) during child slot rendering to optimize updates.

These invisible text nodes interfere with XPath’s contains(text()) functionality. When you try to select elements based on text content, the anchors break your selection logic:

// This might not work as expected in Vue 3
$x(`//button[contains(text(), "Click me")]`);

The Solution: xpath-next

I created xpath-next, a modified XPath polyfill that adds Shadow DOM support and Vue 3 text node compatibility. While non-standard, this approach maintains development velocity without waiting for spec alignment.

You can find it on GitHub: xpath-next

Key Takeaway

As web technologies evolve, previously reliable tools can become incompatible with modern frameworks. Sometimes the practical solution is implementing a custom workaround rather than waiting for ecosystem-wide changes.

Reliable technologies stop being so because the ecosystem moves on and makes them incompatible. Understanding these limitations helps you choose the right tool for your specific context.