Read more

Find the innermost DOM element that contains a given string

Henning Koch
March 02, 2016Software engineer at makandra GmbH

Let's say you want to find the element with the text hello in the following DOM tree:

<html>
  <body>
    <article>
      <strong>hello</strong>
      <strong>world</strong>
    </article>
  </body>
</html>
Illustration online protection

Rails Long Term Support

Rails LTS provides security patches for old versions of Ruby on Rails (2.3, 3.2, 4.2 and 5.2)

  • Prevents you from data breaches and liability risks
  • Upgrade at your own pace
  • Works with modern Rubies
Read more Show archive.org snapshot

You might think of using jQuery's :contains Show archive.org snapshot selector:

$(":contains('hello')")

Unfortunately that returns a lot more elements than you expect:

[ <html>...<html>,
  <body>...</body>,
  <article>...</article>,
  <strong>hello</strong> ]

The reason for this is that all of these elements contain the word hello!

What you need to do instead is to find all elements containing "hello" which don't have a descendant containing "hello":

$(":contains('hello'):not(:has(:contains('hello')))")

Note that :contains and :has are non-standard selectors that are available in jQuery's selector engine only. You can't use them in other libraries that match CSS selectors, such as Nokogiri or Capybara.

You can do the same with an XPath expression, though. So e.g. in Capybara:

page.find(:xpath, ".//*[contains(text(), 'hello') and not (./*[contains(text(), 'hello')])]")
Posted by Henning Koch to makandra dev (2016-03-02 11:22)