Chrome Extension Readability Enhancer — Developer Guide

6 min read

Build a Readability Enhancer Extension — Full Tutorial

What We’re Building

manifest.json — MV3, activeTab + storage permissions, action with icon

Step 1: Manifest Configuration

{
  "permissions": ["activeTab", "storage"],
  "action": { "default_icon": "icon.png" },
  "commands": {
    "toggle-reader": {
      "suggested_key": "Alt+Shift+R",
      "description": "Toggle reader mode"
    }
  }
}

Step 2: Content Script — Extract Main Article Content

// Extract main content using multiple heuristics
function extractArticleContent() {
  // Priority: article > main > largest text block
  const article = document.querySelector('article') || 
                  document.querySelector('main') ||
                  findLargestTextBlock();
  return {
    content: article.cloneNode(true),
    wordCount: article.innerText.split(/\s+/).length
  };
}

function findLargestTextBlock() {
  // Score elements by text density and paragraph count
  const candidates = document.querySelectorAll('div, section');
  // Return element with highest content score
}

Step 3: Reader View Overlay

function createReaderOverlay(content, wordCount) {
  const overlay = document.createElement('div');
  overlay.id = 'reader-view-overlay';
  overlay.innerHTML = `
    <div class="reader-toolbar">...</div>
    <div class="reader-content">${content.innerHTML}</div>
    <div class="reader-progress-bar"></div>
  `;
  document.body.appendChild(overlay);
}

Step 4: Font Controls

.reader-content {
  font-family: var(--reader-font-family, Georgia);
  font-size: var(--reader-font-size, 18px);
  line-height: var(--reader-line-height, 1.6);
  max-width: var(--reader-max-width, 720px);
  margin: 0 auto;
  padding: 2rem;
}

Step 5: Save Preferences to Storage

// Save preferences
async function savePreferences(prefs) {
  await chrome.storage.local.set({ readerPreferences: prefs });
}

// Load preferences
async function loadPreferences() {
  const { readerPreferences } = await chrome.storage.local.get('readerPreferences');
  return readerPreferences || defaultPreferences;
}

Step 6: Reading Progress Bar

function updateProgressBar() {
  const scrollTop = window.scrollY;
  const docHeight = document.documentElement.scrollHeight - window.innerHeight;
  const progress = (scrollTop / docHeight) * 100;
  document.querySelector('.reader-progress-bar').style.width = progress + '%';
}

Step 7: Estimated Reading Time

function calculateReadingTime(wordCount) {
  const minutes = Math.ceil(wordCount / 200);
  return minutes === 1 ? '1 min read' : `${minutes} min read`;
}

Step 8: Keyboard Shortcuts

chrome.commands.onCommand.addListener((command) => {
  if (command === 'toggle-reader') {
    // Send message to content script to toggle
  }
});

Theme Modes

.reader-view-overlay[data-theme="sepia"] {
  --bg-color: #f4ecd8;
  --text-color: #5b4636;
}
@media print {
  .reader-toolbar, .reader-progress-bar { display: none !important; }
  .reader-content { max-width: 100% !important; }
}

Edge Cases & Handling

Cross-References

Testing

What You Learned

Part of the Chrome Extension Guide by theluckystrike. Built at zovo.one.

No previous article
No next article