content-script-developer

from shipshitdev/library

Claude, Cursor, Codex skills and commands

3 stars0 forksUpdated Jan 25, 2026
npx skills add https://github.com/shipshitdev/library --skill content-script-developer

SKILL.md

Content Script Developer

You build reliable, low-impact content scripts for browser extensions (Chrome MV3). You focus on stable DOM integration, safe styling, messaging, and performance on SPA-heavy sites.

When to Use

  • Building or updating a content script
  • Injecting UI into third-party pages
  • Scraping or reading page state in a browser extension
  • Handling SPA navigation changes or dynamic DOM updates

Core Constraints

  • Content scripts run in an isolated world; page JS scope is not shared.
  • Avoid polluting the host page (global styles, conflicting IDs/classes).
  • Be idempotent: injection should not duplicate on re-run.
  • Prefer robust selectors over brittle class chains.
  • Never block the main thread; throttle observers and event handlers.

Workflow

1) Understand the Target Page

  • Identify stable anchors (data attributes, IDs, landmark roles).
  • Note SPA navigation patterns (URL changes, DOM root swaps).
  • Decide what you need: read-only scrape vs UI injection.

2) Plan Injection Safely

  • Create a single root container for your UI.
  • Use a shadow root if CSS conflicts are likely.
  • Add styles with a unique prefix or scoped to your root.
  • Ensure cleanup hooks if the page swaps roots.

3) Handle Dynamic Pages

  • Use a MutationObserver for DOM changes.
  • Throttle work with requestAnimationFrame or debouncing.
  • Re-check anchors on navigation events.

4) Message and Store Data

  • Use chrome.runtime.sendMessage for background/service worker calls.
  • Use chrome.storage for persistent state.
  • Keep tokens or sensitive data in extension storage, not DOM.

5) Accessibility and UX

  • Keyboard-focusable UI elements.
  • Visible focus styles.
  • ARIA labels for controls.

Patterns and Snippets

Idempotent UI Injection

const ROOT_ID = 'ext-root';

export function ensureRoot() {
  let root = document.getElementById(ROOT_ID);
  if (root) return root;

  root = document.createElement('div');
  root.id = ROOT_ID;
  root.setAttribute('data-ext-root', 'true');
  document.body.appendChild(root);
  return root;
}

Safe Styling (Scoped)

const styleId = 'ext-style';

function injectStyles(css: string) {
  if (document.getElementById(styleId)) return;
  const style = document.createElement('style');
  style.id = styleId;
  style.textContent = css;
  document.head.appendChild(style);
}

MutationObserver with Throttle

let scheduled = false;
const observer = new MutationObserver(() => {
  if (scheduled) return;
  scheduled = true;
  requestAnimationFrame(() => {
    scheduled = false;
    // re-check anchors or update UI
  });
});

observer.observe(document.body, { childList: true, subtree: true });

Messaging to Background

async function fetchData(payload: Record<string, unknown>) {
  return await chrome.runtime.sendMessage({ type: 'FETCH_DATA', payload });
}

Reliability Checklist

  • UI injection is idempotent
  • Styles are scoped or shadow-rooted
  • Observers are throttled and cleaned up
  • Messaging uses explicit message types
  • Host page performance remains stable

Common Pitfalls

  • Injecting the same UI multiple times on SPA navigation
  • Using brittle selectors that break on minor DOM changes
  • Global CSS that overrides host styles
  • Heavy MutationObserver handlers without throttling

Notes

  • Prefer small, composable helpers over large one-off scripts.
  • Keep extension logging prefixed and easy to disable in production.

Repository Stats

Stars3
Forks0