Skip to content

Instantly share code, notes, and snippets.

@micartey
Created February 6, 2026 13:18
Show Gist options
  • Select an option

  • Save micartey/4efaaae678ecf33be133c9d720db258d to your computer and use it in GitHub Desktop.

Select an option

Save micartey/4efaaae678ecf33be133c9d720db258d to your computer and use it in GitHub Desktop.
// ==UserScript==
// @name GitHub SVG Inline & Selectable
// @namespace http://tampermonkey.net/
// @version 1.0
// @description Replaces img tags with inline SVGs on GitHub to allow text selection, removing wrapping links.
// @author You
// @match https://github.com/*
// @grant none
// ==/UserScript==
(function() {
'use strict';
// The core conversion logic
function convertSvgs() {
const selector = 'img[src$=".svg"]:not([data-svg-processed])';
document.querySelectorAll(selector).forEach(async img => {
// Mark immediately to prevent double-fetching during async wait
img.setAttribute('data-svg-processed', 'true');
try {
const response = await fetch(img.src);
if (!response.ok) throw new Error('Fetch failed');
const text = await response.text();
const parser = new DOMParser();
const doc = parser.parseFromString(text, 'image/svg+xml');
const svg = doc.documentElement;
// Check for parsing errors
if (svg.querySelector('parsererror')) return;
// Styling for selection
svg.style.userSelect = 'text';
svg.style.cursor = 'text';
svg.querySelectorAll('text, tspan').forEach(t => {
t.style.userSelect = 'text';
t.style.cursor = 'text';
});
// Find parent link to remove
const parentLink = img.closest('a');
const targetToReplace = parentLink ? parentLink : img;
targetToReplace.replaceWith(svg);
} catch (e) {
console.debug('SVG Conversion failed for:', img.src, e);
// Revert attribute so we can retry if needed, or leave to ignore
img.removeAttribute('data-svg-processed');
}
});
}
// Run on initial load
convertSvgs();
// Run on GitHub Page Navigation (Turbo/Pjax events)
document.addEventListener('turbo:load', convertSvgs);
document.addEventListener('turbo:render', convertSvgs);
// Observer for lazy-loaded images (e.g. inside long READMEs)
const observer = new MutationObserver((mutations) => {
let shouldRun = false;
mutations.forEach(m => {
if (m.addedNodes.length > 0) shouldRun = true;
});
if (shouldRun) convertSvgs();
});
observer.observe(document.body, { childList: true, subtree: true });
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment