Advanced Features
This page covers the advanced features of astro-smart-links: custom link structures, link transforms and a complete configuration. Every preview is the real output of that config.
Custom Link Structure
Section titled “Custom Link Structure”Fully control the link HTML with wrapperTemplate. The callback receives (node, type, meta) and returns the replacement node; meta.className holds the configured class for the link type:
Custom Link Structure
import { smartLinks } from 'astro-smart-links';import { h } from 'hastscript';
smartLinks({ wrapperTemplate: (node, type, meta) => { const icons = { internal: ['after', '📄'], external: ['after', '🔗'], broken: ['before', '⚠️'], }; const [position, icon] = icons[type];
if (position === 'before') { node.children.unshift(h('span', { className: 'mr-1' }, icon)); } else { node.children.push(h('span', { className: 'ml-1' }, icon)); }
node.properties.className = [ ...(node.properties.className || []), meta.className, 'flex', 'items-center', 'gap-1', ];
return node; },}),Adding Badges
Section titled “Adding Badges”Append a label to make the link type obvious:
Adding Badges
import { smartLinks } from 'astro-smart-links';import { h } from 'hastscript';
smartLinks({ wrapperTemplate: (node, type, meta) => { const badges = { internal: ['badge badge-primary badge-sm', 'Internal'], external: ['badge badge-secondary badge-sm', 'External'], broken: ['badge badge-error badge-sm', 'Missing'], }; const [className, label] = badges[type];
node.children.push(h('span', { className }, label)); node.properties.className = [ ...(node.properties.className || []), meta.className, 'flex', 'items-center', 'gap-2', ];
return node; },}),Link Transforms
Section titled “Link Transforms”customInternalLinkTransform, customExternalLinkTransform and customBrokenLinkTransform modify nodes per link type. Each callback receives (node, meta). Custom transforms take over the link entirely, so apply meta.className yourself:
Link Transforms
import { smartLinks } from 'astro-smart-links';
smartLinks({ customInternalLinkTransform: (node, meta) => { node.properties.className = [...(node.properties.className || []), meta.className]; if (meta.pathname?.includes('demo')) { node.properties['data-section'] = 'demos'; } }, customExternalLinkTransform: (node, meta) => { node.properties.className = [...(node.properties.className || []), meta.className]; node.properties.target = '_blank'; node.properties.rel = 'noopener noreferrer'; node.properties['data-external'] = 'true';
if (meta.href.includes('github.com')) { node.properties.className.push('github-link'); } }, customBrokenLinkTransform: (node, meta) => { node.properties.className = [...(node.properties.className || []), meta.className]; node.properties['data-error'] = 'true'; node.properties.title = 'This page does not exist'; },}),Ignoring Links
Section titled “Ignoring Links”Links matched by ignore are left completely untouched: no classes, no target/rel, no icon, and they are excluded from broken-link checks. All other links are processed as usual:
Ignoring Links
Internal Link
External Link
Broken Link
import { smartLinks } from 'astro-smart-links';
smartLinks({ // RegExp patterns match both locales, e.g. /draft/ and /en/draft/ ignore: [/\/draft\//, /\/preview\//],}),Complete Configuration
Section titled “Complete Configuration”A complete example combining the most common options:
Complete Configuration
import { defineConfig } from 'astro/config';import { smartLinks } from 'astro-smart-links';
export default defineConfig({ integrations: [ smartLinks({ internalLinkClass: 'internal-link', externalLinkClass: 'external-link', brokenLinkClass: 'broken-link', target: '_blank', rel: 'noopener noreferrer', ignore: ['/draft/'],
// Broken link handling failOnBroken: true, reportFile: '.smart-links-report.json', }), ],});Next Steps
Section titled “Next Steps”Keep exploring:
- Custom CSS - Add animations and hover effects with plain CSS
- Custom Icons - Add icons for each link type