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 ofqueryin the text underrootin<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 queryjavascript. 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.innerHTMLis 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.