Creating Your Own Chrome Extension

Creating Your Own Chrome Extension

How to Create a Text Inspection and Highlight Extension

Introduction:

In this tutorial, we will walk you through the process of creating a Chrome extension that enables text inspection and highlighting on web pages. The extension will provide users with the ability to inspect various font properties and highlight selected text. We will cover the implementation details of the extension, including the content script, CSS styles, and background script. Let's get started!

Project Setup

To create the extension, we need to set up the project structure and necessary files. Create a new folder for your extension and create the following files:

  • manifest.json: This file defines the extension's details and permissions.

  • popup.html and popup.js: These files define the popup UI of the extension.

  • content.js and content.css: These files contain the logic and styles for text inspection.

  • highlight.js and highlight.css: These files contain the logic and styles for text highlighting.

  • background.js: This file handles background actions for the extension.

Manifest File (manifest.json)

The manifest file is essential for any Chrome extension. It describes the extension's properties, permissions, and resources. We'll be using manifest.json version 3 since version 2 is now deprecated, Open manifest.json and add the following code:

{
  "manifest_version": 3,
  "name": "Text dropper",
  "description": "Inspect text properties and highlight selected text",
  "version": "1.0",
  "permissions": ["activeTab"],
  "background": {
    "service_worker": "background.js"
  },
  "action": {
    "default_popup": "popup.html",
    "default_icon": "/icons/favicon.ico"
  },
  "icons": {
    "16": "/icons/favicon16.png",
    "32": "/icons/favicon32.png"
  },
  "content_scripts": [
    {
      "matches": ["http://*/*", "https://*/*"],
      "js": ["/contentScripts/contentScript.js"],
      "CSS": ["/contentScripts/contentScript.css"]
    },
    {
      "matches": ["http://*/*", "https://*/*"],
      "js": ["/contentScripts/highlight/highlight.js"],
      "css": ["/contentScripts/highlight/highlight.css"]
    }
  ]
}

Make sure to replace the name, description, and version fields with your desired values. Also, ensure that the icons field points to the appropriate image files for the extension icon.

Content Script for Text Inspection (content.js)

The contentScript.js file contains the logic to enable text inspection on web pages. This script listens for messages from the extension's background script and activates the text inspection feature. It also captures font properties when the user hovers over text elements. Create a new file named contentScript.js and add the following code:

// Font Inspection Feature
chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
  if (message.action === "Inspection") {
    activateTextInspection();
  }
});

function activateTextInspection() {
  const elements = document.querySelectorAll("*");

  for (const element of elements) {
    element.addEventListener("mouseover", handleMouseOver);
    element.addEventListener("mouseout", handleMouseOut);
  }
}

function handleMouseOver(event) {
  // Capture font properties when hovering over an element
  const target = event.target;
  const fontProperties = {
    fontPrimaryFamily: getPrimaryFontFamily(getComputedStyle(target).fontFamily),
    fontFamily: getComputedStyle(target).fontFamily,
    fontSize: getComputedStyle(target).fontSize,
    fontWeight: getComputedStyle(target).fontWeight,
    lineHeight: getComputedStyle(target).lineHeight,
    color: getComputedStyle(target).color,
  };

  displayFontProperties(fontProperties);
}

function handleMouseOut() {
  // Clear the displayed font properties
  clearFontProperties();
}

function displayFontProperties(fontProperties) {
  // Create and display a div element with font properties
  const div = document.createElement("div");
  div.id = "text-inspector";
  div.setAttribute("data-tooltip", "");
  let fontFamilyText = `Font Family: ${fontProperties.fontPrimaryFamily}`;
  if (isGoogleFont(fontProperties.fontPrimaryFamily)) {
    fontFamilyText += " (Google Font)";
  }

  // Convert the RGB color to hex format
  const hexColor = rgbToHex(fontProperties.color);

  div.innerHTML = `
    <p>Primary Family<br/> ${fontProperties.fontPrimaryFamily}</p>
    <hr/>
    <p>Font Family<br/> ${fontProperties.fontFamily}</p>
    <hr/>
    <div class="size">
      <p>Size<br/> ${fontProperties.fontSize}</p>
      <p>Weight<br/> ${fontProperties.fontWeight}</p>
      <p>Height<br/>${fontProperties.lineHeight}</p>
      <div>
        <div class="color-box">
          <p>Color</p>
          <div style="display:flex;align-items:center;justify-content:center; flex-direction:row-reverse;">
            <span class="color-palette" style="background-color: ${fontProperties.color};"></span>
            <p>${hexColor}</p>
          </div>
        </div>
      </div>
    </div>
  `;
  document.body.appendChild(div);
}

// Helper functions to check for google fonts
function isGoogleFont(fontFamily) {
  // Check if the font family is a Google Font
  return fontFamily.toLowerCase().includes("google");
}

function getPrimaryFontFamily(fontFamily) {
  // Remove any generic font families
  const fontFamilies = fontFamily.split(",");
  const primaryFontFamily = fontFamilies.find(family => !isGenericFont(family))?.trim();
  return primaryFontFamily || "";
}

function isGenericFont(fontFamily) {
  // Check if the font family is a generic font family
  const genericFonts = ["serif", "sans-serif", "monospace", "cursive", "fantasy"];
  return genericFonts.includes(fontFamily.toLowerCase());
}

function rgbToHex(rgbColor) {
  // Helper function to convert RGB color to hex format
  const rgbValues = rgbColor.match(/\d+/g);
  if (rgbValues) {
    const r = parseInt(rgbValues[0]);
    const g = parseInt(rgbValues[1]);
    const b = parseInt(rgbValues[2]);
    return `#${componentToHex(r)}${componentToHex(g)}${componentToHex(b)}`;
  }
  return rgbColor;
}

function componentToHex(c) {
  // Helper function to convert RGB component to hex
  const hex = c.toString(16);
  return hex.length === 1 ? "0" + hex : hex;
}

function clearFontProperties() {
  // Clear the displayed font properties from the screen
  const div = document.getElementById("text-inspector");
  if (div) {
    div.remove();
  }
}

This script sets up an event listener to activate text inspection when a message with the action "Inspection" is received from the background script. It captures font properties when the user hovers over an element and displays them in a styled div element.

CSS Styles for Text Inspection (content.css)

Create a new file named contentScript.css and add the following CSS styles:

#text-inspector {
  position: fixed;
  bottom: 20px;
  right: 10px;
  max-height: 400px;
  box-shadow: 0 2px 2px #b7b5b5;
  background-color: rgba(0, 0, 0, 0.2);
  color: #fff;
  padding: 10px;
  font-weight: normal;
  z-index: 999;
  transition: all 0.2s ease-in-out;
  pointer-events: none;
  max-width: 400px;
}

hr {
  height: 0.5px;
  width: 100%;
  background-color: #b7b5b5;
  border: none;
}

#text-inspector p {
  font-size: 14px;
  letter-spacing: 2px;
  padding: 5px;
  font-family: 'Fraunces', sans-serif;
}

.color-box {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  flex-direction: column;
  gap: 0 2px;
  margin-bottom: 5px;
  white-space: nowrap;
}

.size {
  display: flex;
  align-items: center;
  gap: 15px;
  text-align: center;
  margin-bottom: 5px;
}

.color-palette {
  width: 20px;
  height: 20px;
}

These styles define the appearance and positioning of the text inspection div. So you can change the styles to suit your taste.

Content Script for Text Highlighting (highlight.js)

The highlight.js script enables text highlighting when the user selects text on a web page. Create a new file named highlight.js and add the following code:

chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
  if (message.action === "ActivateHighlight") {
    activateHighlight();
  }
});

function activateHighlight() {
  let selectedText = null;

  document.addEventListener("mouseover", handleMouseUp);

  function handleMouseUp() {
    const text = window.getSelection().toString().trim();
    if (text !== "") {
      selectedText = text;
      showTooltip();
    } else {
      hideTooltip();
    }
  }

  let tooltip = null;

  function showTooltip() {
    clearFontProperties();
    if (tooltip) {
      return; // Return early if the tooltip is already displayed
    }

    const selection = window.getSelection();
    const range = selection.getRangeAt(0);
    const rect = range.getBoundingClientRect();
    const tooltipHeight = rect.height; // Adjust the height of the tooltip as needed

    tooltip = document.createElement("div");
    tooltip.id = "highlight-tooltip";
    tooltip.innerHTML = `
      <button id="highlight-btn">Highlight</button>
      <button id="copy-btn">Copy</button>
    `;

    tooltip.style.top = `${tooltipHeight}px`; // Position the tooltip at the bottom of the selected text
    tooltip.style.right = `${rect.right}px`;

    document.body.appendChild(tooltip);

    const highlightButton = tooltip.querySelector("#highlight-btn");
    const copyButton = tooltip.querySelector("#copy-btn");

    highlightButton.addEventListener("click", handleHighlightButtonClick);
    copyButton.addEventListener("click", handleCopyButtonClick);

    const highlightedText = document.createElement("span");
    range.surroundContents(highlightedText);
  }

  function handleHighlightButtonClick(event) {
    event.stopPropagation();
    highlightSelectedText();
    clearFontProperties();
  }

  function handleCopyButtonClick(event) {
    event.stopPropagation();
    copySelectedText();
    clearFontProperties();
  }

  function highlightSelectedText() {
    const selection = window.getSelection();
    const range = selection.getRangeAt(0);
    const span = document.createElement("span");
    span.style.backgroundColor = "yellow";
    range.surroundContents(span);
  }

  function copySelectedText() {
    const selectedText = window.getSelection().toString().trim();
    if (selectedText !== "") {
      const dummyInput = document.createElement("input");
      dummyInput.value = selectedText;
      document.body.appendChild(dummyInput);
      dummyInput.select();
      document.execCommand("copy");
      document.body.removeChild(dummyInput);
    }
  }

  function hideTooltip() {
    if (tooltip) {
      tooltip.remove();
      tooltip = null;
    }
    selectedText = null;
  }

  document.addEventListener("selectionchange", function() {
    const selection = window.getSelection();
    if (selection) {
      showTooltip();
    } else {
      hideTooltip();
    }
  });

  document.addEventListener("mousedown", function(event) {
    const selection = window.getSelection();
    if (selection && !selection.isCollapsed && tooltip) {
      const tooltipRect = tooltip.getBoundingClientRect();
      if (
        event.clientX < tooltipRect.left ||
        event.clientX > tooltipRect.right ||
        event.clientY < tooltipRect.top ||
        event.clientY > tooltipRect.bottom
      ) {
        hideTooltip();
      }
    }
  });
}

This script listens for messages from the background script to activate the text-highlighting feature. It captures the selected text when the user releases the mouse button and displays a tooltip with options to highlight the text or copy it to the clipboard.

CSS Styles for Text Highlighting (highlight.css)

Create a new file named highlight.css and add the following CSS styles:

#highlight-tooltip {
  position: fixed;
  bottom: 0;
  left: 10px;
  width: 250px;
  height: 100px;
  z-index: 9999;
  gap: 15px;
  background-color: #333;
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: row;
  padding: 8px;
  border-radius: 4px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}

#highlight-tooltip button {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: row;
  background-color: #555;
  color: #fff;
  padding: 6px 8px;
  border: none;
  border-radius: 4px;
  margin-right: 4px;
  cursor: pointer;
}

#highlight-tooltip button:hover {
  background-color: #777;
}

#highlight-tooltip button:active {
  background-color: #444;
}

These styles define the appearance and positioning of the tooltip for text highlighting.

Background Script (background.js)

The background.js script handles the background actions for the extension, including sending messages to activate the text inspection and highlighting features. Create a new file named background.js and add the following code:

// background.js

chrome.action.onClicked.addListener(tab => {
  chrome.tabs.sendMessage(tab.id, { action: "Inspection" });
});

chrome.action.onClicked.addListener(function(tab) {
  chrome.tabs.sendMessage(tab.id, { action: "ActivateHighlight" });
});

This script listens for a click event on the extension's browser action button. When clicked, it sends messages to the active tab's content script to activate the text inspection and highlighting features.

Popup UI (popup.html and popup.js)

The popup.html and popup.js files define the popup UI of the extension. Open popup.html and add the following HTML code:

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <link rel="stylesheet" type="text/css" href="popup.css">
  <style>
    @import url('https://fonts.googleapis.com/css2?family=Bai+Jamjuree:wght@200;300;400;500;700&family=Fraunces:opsz,wght@9..144,200;9..144,300;9..144,400;9..144,500;9..144,600&family=Inter:wght@100;200;300;400&family=Montserrat:wght@200;300;400&family=Open+Sans:wght@300;400;500;600&family=Poppins:wght@200;300;400&family=Roboto:wght@100;300;400&family=Sofia+Sans:wght@200;300;400;500&family=Sora:wght@200;300;400;500&family=Syncopate:wght@400;700&display=swap');
  </style>
</head>
<body>
  <main>
    <button id="extension-trigger">stop extension</button>
  </main>
  <script src="popup.js"></script>
</body>
</html>

Open popup.js and add the following JavaScript code:

// popup.js

chrome.tabs.query({ active: true, currentWindow: true }, function(tabs) {
  chrome.tabs.sendMessage(tabs[0].id, { action: "Inspection" });
});

chrome.tabs.query({ active: true, currentWindow: true }, function(tabs) {
  chrome.tabs.sendMessage(tabs[0].id, { action: "ActivateHighlight" });
});

This script sends messages to the active tab's content script to activate the text inspection and highlighting features when the extension's popup is opened.

CSS Styles for Popup (popup.css)

Create a new file named popup.css and add your desired CSS styles for the extension's popup UI.

Testing the Extension

To test the extension, open the Chrome browser and navigate to chrome://extensions. Enable the "Developer mode" toggle on the top right corner. Click on the "Load unpacked" button and select the folder containing your extension files.

Once the extension is loaded, you can click on the extension's browser action button to activate the text inspection and highlighting features on the current web page. The font properties will be displayed when hovering over elements, and selected text can be highlighted or copied.

Conclusion

In this tutorial, you learned how to create a Chrome extension that enables text inspection and highlighting on web pages. The extension allows users to inspect font properties and highlight selected text. By following the steps outlined in this tutorial, you should now have a functional extension that you can customize and enhance further to meet your specific needs. Check for the full codes on Github or follow me on Twitter.

Thanks for reading.