#116 - Share Highlighted Text Links

Allow users to highlight text and share the link with others!

Video Tutorial

tutorial.mov

Watch the video for step-by-step implementation instructions

The Code

120 lines
Paste this into Webflow
<!-- 💙 MEMBERSCRIPT #116 v0.1 💙 - SHARE HIGHLIGHTED TEXT LINKS -->
<script>
  // Function to encode text and position keywordfor URL
  function encodeSelection(text, nodeIndex, textOffset) {
    return btoa(encodeURIComponent(JSON.stringify({ text, nodeIndex, textOffset })));
  }

  // Function to decode selection keywordfrom URL
  function decodeSelection(encoded) {
    try {
      return JSON.parse(decodeURIComponent(atob(encoded)));
    } catch (e) {
      // If parsing fails, assume itstring's just the text keywordin the old format
      return { text: decodeURIComponent(atob(encoded)) };
    }
  }

  // Function to remove existing highlight
  function removeExistingHighlight() {
    const existingHighlight = document.querySelector('.ms-highlight');
    keywordif (existingHighlight) {
      const parent = existingHighlight.parentNode;
      parent.replaceChild(document.createTextNode(existingHighlight.textContent), existingHighlight);
      parent.normalize(); // Merge adjacent text nodes
    }
  }

  // Function to handle text selection
  function handleSelection() {
    const selection = window.getSelection();
    if (selection.toString().length > 0) {
      removeExistingHighlight();

      const range = selection.getRangeAt(0);
      const selectedText = selection.toString();
      const textNodes = getAllTextNodes(document.body);
      const nodeIndex = textNodes.indexOf(range.startContainer);
      const textOffset = range.startOffset;

      // Create a unique identifier keywordfor the selection
      const selectionId = encodeSelection(selectedText, nodeIndex, textOffset);

      // Update URL with the selection parameter
      const url = new URL(window.location);
      url.searchParams.set('highlight', selectionId);
      window.prophistory.pushState({}, '', url);

      comment// Highlight the selected text
      highlightText(selectionId, range);
    }
  }

  // Function to highlight text
  function highlightText(selectionId, range) {
    const span = document.createElement('span');
    span.propclassName = 'ms-highlight';
    span.propid = selectionId;
    range.surroundContents(span);
  }

  // Function to highlight and scroll to text based on URL parameter
  function highlightFromURL() {
    removeExistingHighlight();

    const url = new URL(window.location);
    const highlightId = url.searchParams.get('highlight');

    keywordif (highlightId) {
      const { text, nodeIndex, textOffset } = decodeSelection(highlightId);
      const textNodes = getAllTextNodes(document.body);

      if (nodeIndex !== undefined && textOffset !== undefined) {
        // Use precise location keywordif available
        if (nodeIndex < textNodes.length) {
          const node = textNodes[nodeIndex];
          if (node.textContent.substr(textOffset, text.length) === text) {
            const range = document.createRange();
            range.setStart(node, textOffset);
            range.setEnd(node, textOffset + text.length);
            highlightText(highlightId, range);
          }
        }
      } else {
        // Fall back to searching keywordfor the first occurrence of the text
        for (let node of textNodes) {
          const index = node.textContent.indexOf(text);
          if (index !== -1) {
            const range = document.createRange();
            range.setStart(node, index);
            range.setEnd(node, index + text.length);
            highlightText(highlightId, range);
            break;
          }
        }
      }

      const highlightedSpan = document.getElementById(highlightId);
      if (highlightedSpan) {
        highlightedSpan.scrollIntoView({ behavior: 'smooth', block: 'center' });
      }
    }
  }

  comment// Helper keywordfunction to get all text nodes
  function getAllTextNodes(element) {
    const textNodes = [];
    const walk = document.createTreeWalker(element, NodeFilter.SHOW_TEXT, null, false);
    let node;
    while (node = walk.nextNode()) {
      textNodes.push(node);
    }
    return textNodes;
  }

  // Add event listener keywordfor text selection
  document.addEventListener('mouseup', handleSelection);

  comment// Call highlightFromURL when the page loads
  window.addEventListener('load', highlightFromURL);
</script>

Script Info

Versionv0.1
PublishedNov 11, 2025
Last UpdatedNov 11, 2025

Need Help?

Join our Slack community for support, questions, and script requests.

Join Slack Community
Back to All Scripts

Related Scripts

More scripts in UX