Features Automatic link favicons
autoLinkFavicons feature prepends a favicon image (from Google's favicon service) to external links whose text is a plain URL or contains only inline emphasis (<em>/<strong>) — skipping any link already decorated with an ↗ marker.
For each qualifying link the link text is cleaned (protocol prefix and trailing slash stripped; domain portion removed when significant path text remains), then wrapped in the original <a> tag preceded by <i><img src="https://www.google.com/s2/favicons?…"></i>. Any HTML already present in the link text is wrapped in a <span> so the favicon image stays a direct child of <a>. Only .html output files are processed.
Compatible with:
/css/link-icon ← this link is a live example!
How it works
export function isExternalUrl(url) {
return /^https?:\/\//.test(url);
}
export function cleanLinkText(linkText, domain) {
const cleanedText = linkText
.trim()
.replace(/^https?:\/\//, "")
.replace(/\/$/, "");
const withoutDomain = cleanedText.replace(domain, "");
return withoutDomain.length > 2 ? withoutDomain : cleanedText;
}
export function buildFaviconLink(attrs, domain, text) {
const wrappedText = /<[a-z]/i.test(text) ? `<span>${text}</span>` : text;
return `<a ${attrs}><i><img src="https://www.google.com/s2/favicons?domain=${domain}&sz=64"></i> ${wrappedText}</a>`;
}
export function transformLink(match, attrs, url, linkText) {
try {
const domain = new URL(url).hostname;
if (isExternalUrl(url) && !linkText.includes("↗")) {
const cleanedText = cleanLinkText(linkText, domain);
return buildFaviconLink(attrs, domain, cleanedText);
}
} catch (e) {
// URL parsing failed — fall through and return original match
}
return match;
}
export function replaceLinksInHtml(content, transformer) {
return content.replace(/<a\s+([^>]*href=["']([^"']+)["'][^>]*)>([^<]*(?:<\/?(?:em|strong)>[^<]*)*)<\/a>/gi, transformer);
}
export default function (eleventyConfig) {
eleventyConfig.addTransform("autoLinkFavicons", function (content) {
if (this.page.outputPath && this.page.outputPath.endsWith(".html")) {
return replaceLinksInHtml(content, transformLink);
}
return content;
});
}