Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Enhancing Text Selection and Styling with the Custom Highlight API

Tech 2

The Custom Highlight API enables developers to apply CSS styles to specific text ranges defined in JavaScript without modifying the DOM. This approach avoids the performance overhead and structural complications associated with inserting <span> elements.

A typical workflow involves:

  1. Obtaining a text node (e.g., document.querySelector('p').firstChild).
  2. Creating a Range object and defining its start and end points.
  3. Registering this range with the API using CSS.highlights.set() and assigning it a name.
  4. Applying styles via the CSS ::highlight() pseudo-element with that name.

For instance, to highlight the first occurrence of a specific word within a paragraph:

const targetWord = 'example';
const highlightId = 'custom-highlight';

const textElement = document.querySelector('p').firstChild;
const fullText = textElement.textContent;

const wordStart = fullText.indexOf(targetWord);
const wordEnd = wordStart + targetWord.length;

const textRange = new Range();
textRange.setStart(textElement, wordStart);
textRange.setEnd(textElement, wordEnd);

const highlightObj = new Highlight(textRange);
CSS.highlights.set(highlightId, highlightObj);

Corresponding CSS:

::highlight(custom-highlight) {
    background-color: yellow;
    color: black;
}

This technique mirrors how browsers internally style text for features like the find-in-page tool, leaving the DOM structure untouched.

Key Advantages

  • Performance: Eliminates the need for DOM manipulation, which can be costly when dealing with large volumes of text nodes.
  • Integrity: Prevents potential side effects on other CSS or JavaScript that relies on a stable DOM structure.
  • Scalability: Reduces DOM complexity, which is a known factor impacting rendering performance, animations, and scroll smoothness.

Implementing a Search Feature

A primary use case is building a custom search interface. The Highlight constructor can accept multiple Range objects, allowing a single style rule to apply to all matches.

HTML:

<label>
    Search text:
    <input type="search" id="searchInput" value="sample">
</label>
<p id="content">This is a sample paragraph with sample text.</p>

JavaScript:

const searchField = document.getElementById('searchInput');
const contentPara = document.getElementById('content');
const textNode = contentPara.firstChild;

searchField.addEventListener('input', (event) => {
    performSearch(event.target.value);
});

function performSearch(term) {
    // Clear previous highlights
    CSS.highlights.clear();

    if (!term) return;

    const regex = new RegExp(term, 'gi');
    const content = textNode.textContent;
    const matches = [...content.matchAll(regex)];

    const matchRanges = matches.map(match => {
        const range = new Range();
        range.setStart(textNode, match.index);
        range.setEnd(textNode, match.index + term.length);
        return range;
    });

    if (matchRanges.length > 0) {
        const searchHighlight = new Highlight(...matchRanges);
        CSS.highlights.set('search-matches', searchHighlight);
    }
}

CSS for styling matches:

::highlight(search-matches) {
    background-color: #ffeb3b;
    text-decoration: underline wavy red;
}

Application in Syntax Highlighting

This API is well-suited for client-side syntax highlighting, as demonstrated by implementations that use parsers like Prism.js but apply styles via ranges instead of <span> elements. This can significantly reduce the number of DOM nodes.

However, a consideration is that highlighting occurs client-side, which may introduce a visible delay between rendering the raw code and applying the styles. For performance-critical applications, server-side rendering of syntax-highlighted HTML might still be preferable, provided the resulting markup remains performant and accsesible.

The API offers a powerful, low-level method for precise text styling, beneficial for features like search, annotation, and dynamic highlighting where DOM manipulation is undesirable.

Tags: javascript

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.