Custom Icons
This page shows how to use wrapperTemplate to add icons to link types: inline SVG, icon libraries, or icons chosen dynamically from the link destination. Every preview is the real output of that config.
SVG Icons
Section titled “SVG Icons”Build SVG icons with hastscript and insert them into the link, applying the default class with meta.className:
SVG Icons
import { smartLinks } from 'astro-smart-links';import { h } from 'hastscript';
const icons = { internal: 'M13 7l5 5m0 0l-5 5m5-5H6', external: 'M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14', broken: 'M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z',};
smartLinks({ wrapperTemplate: (node, type, meta) => { const svg = h('svg', { className: 'w-4 h-4', fill: 'none', stroke: 'currentColor', viewBox: '0 0 24 24', xmlns: 'http://www.w3.org/2000/svg', }, [ h('path', { 'stroke-linecap': 'round', 'stroke-linejoin': 'round', 'stroke-width': '2', 'd': icons[type], }), ]);
if (type === 'broken') { node.children.unshift(svg); } else { node.children.push(svg); }
node.properties.className = [ ...(node.properties.className || []), meta.className, 'inline-flex', 'items-center', 'gap-1', ];
return node; },}),Icon Animation
Section titled “Icon Animation”Combine group and transition utilities for hover animations:
Icon Animation
import { smartLinks } from 'astro-smart-links';import { h } from 'hastscript';
const animations = { internal: 'transition-transform group-hover:translate-x-1', external: 'transition-transform group-hover:-translate-y-1 group-hover:translate-x-1', broken: 'text-red-500 transition-transform group-hover:rotate-12',};
const icons = { internal: 'M13 7l5 5m0 0l-5 5m5-5H6', external: 'M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14', broken: 'M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z',};
smartLinks({ wrapperTemplate: (node, type, meta) => { const svg = h('svg', { className: `w-4 h-4 ${animations[type]}`, fill: 'none', stroke: 'currentColor', viewBox: '0 0 24 24', xmlns: 'http://www.w3.org/2000/svg', }, [ h('path', { 'stroke-linecap': 'round', 'stroke-linejoin': 'round', 'stroke-width': '2', 'd': icons[type], }), ]);
if (type === 'broken') { node.children.unshift(svg); } else { node.children.push(svg); }
node.properties.className = [ ...(node.properties.className || []), meta.className, 'group', 'inline-flex', 'items-center', 'gap-1', ];
return node; },}),Font Awesome Icons
Section titled “Font Awesome Icons”Use an icon library’s class names (the library stylesheet must be loaded):
Font Awesome Icons
import { smartLinks } from 'astro-smart-links';import { h } from 'hastscript';
const icons = { internal: 'fa fa-book', external: 'fa fa-external-link', broken: 'fa fa-exclamation-triangle',};
smartLinks({ wrapperTemplate: (node, type, meta) => { const icon = h('i', { className: icons[type] });
if (type === 'broken') { node.children.unshift(icon); } else { node.children.push(icon); }
node.properties.className = [ ...(node.properties.className || []), meta.className, 'inline-flex', 'items-center', 'gap-2', ];
return node; },}),Icons Based on Destination
Section titled “Icons Based on Destination”meta.href contains the link target, so you can pick an icon per destination:
Icons Based on Destination
import { smartLinks } from 'astro-smart-links';import { h } from 'hastscript';
const githubIcon = { type: 'element', tagName: 'svg', properties: { className: ['w-4', 'h-4'], viewBox: '0 0 24 24', fill: 'currentColor', xmlns: 'http://www.w3.org/2000/svg', }, children: [{ type: 'element', tagName: 'path', properties: { d: 'M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z' }, children: [], }],};
smartLinks({ wrapperTemplate: (node, type, meta) => { node.properties.className = [...(node.properties.className || []), meta.className];
if (type !== 'external') { return node; }
node.properties.className.push('inline-flex', 'items-center', 'gap-2');
if (meta.href.includes('github.com')) { node.children.push(githubIcon); } else { node.children.push(h('svg', { className: 'w-4 h-4', fill: 'none', stroke: 'currentColor', viewBox: '0 0 24 24', xmlns: 'http://www.w3.org/2000/svg', }, [ h('path', { 'stroke-linecap': 'round', 'stroke-linejoin': 'round', 'stroke-width': '2', 'd': 'M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14', }), ])); }
return node; },}),Next Steps
Section titled “Next Steps”Keep exploring:
- Advanced Features - Custom transforms and complete configuration
- Custom CSS - Define link animations with plain CSS