FrontendPro

98Implement a DOM-based text highlighter that preserves existing markup

mediumAbout 45 minutesCodingdomtexttreewalkersearch

Problem

element.innerHTML = html.replace(query, "<mark>…</mark>") is the classic wrong answer: it can break tags and attributes, opens an XSS hole, and destroys event listeners and component state on every element it re-creates.

Implement, using DOM APIs only:

  • highlight(root, query, { className = "highlight" } = {}): wrap every case-insensitive occurrence of query in the text under root in <mark class="{className}">, and return the number of matches.
  • clearHighlights(root, { className = "highlight" } = {}): remove those marks and restore the original text nodes.

Requirements

  • Never replace existing elements: the same nodes, with their listeners, must remain in the DOM.
  • A match may span several text nodes, for example Java<strong>Script</strong> for the query javascript. Wrap each part in its own <mark> (a mark cannot cross an element boundary).
  • Treat the query as plain text: a+b (c) matches literally.
  • Ignore text inside <script>, <style> and <textarea>.
  • After clearHighlights, root.innerHTML is exactly what it was before.

Try it yourself

Write your solution, run it, then submit to check it against the tests.

App.jsxReact + DOM

Step-by-step

document.createTreeWalker(root, NodeFilter.SHOW_TEXT) visits only text nodes, in document order. Skip nodes whose parent is inside script, style or textarea.

Unlock the full solution

What's inside

  • Step-by-step
  • Approach
  • Solution
  • Complexity
  • Edge cases
  • Follow-up questions
  • Tests

Includes 2 code listings, 5 edge cases, 4 follow-up questions.

One-time payment by UPI, card or net banking. Launch price.

All 150 answersOne payment, yours forever