Tailwind CSS Style Integration
This page demonstrates how to use Tailwind CSS to customize links processed by the rehype-smart-links plugin.
Basic Tailwind Integration
The simplest way to use Tailwind with rehype-smart-links is to add Tailwind classes directly:
Basic Tailwind Classes
// astro.config.mjs
import { defineConfig } from 'astro/config';
import rehypeSmartLinks from 'rehype-smart-links';
export default defineConfig({
markdown: {
rehypePlugins: [[
rehypeSmartLinks,
{
internalLinkClass: 'text-blue-600 hover:text-blue-800 underline',
externalLinkClass: 'text-purple-600 hover:text-purple-800 underline',
brokenLinkClass: 'text-red-600 hover:text-red-800 line-through'
}
]]
}
});
Advanced Tailwind Styling
Create more sophisticated link styles with Tailwind’s utility classes:
Advanced Tailwind Styling
// astro.config.mjs
import { defineConfig } from 'astro/config';
import rehypeSmartLinks from 'rehype-smart-links';
export default defineConfig({
markdown: {
rehypePlugins: [[
rehypeSmartLinks,
{
internalLinkClass: 'inline-flex items-center px-3 py-1 text-sm rounded-full bg-blue-100 text-blue-700 hover:bg-blue-200 transition-colors duration-200',
externalLinkClass: 'inline-flex items-center px-3 py-1 text-sm rounded-full bg-purple-100 text-purple-700 hover:bg-purple-200 transition-colors duration-200',
brokenLinkClass: 'inline-flex items-center px-3 py-1 text-sm rounded-full bg-red-100 text-red-700 line-through opacity-75 cursor-not-allowed'
}
]]
}
});
Custom Icons with Tailwind
Add icons to your links using Tailwind’s flex utilities:
Links with Tailwind Icons
// astro.config.mjs
import { defineConfig } from 'astro/config';
import rehypeSmartLinks from 'rehype-smart-links';
import { h } from 'hastscript';
export default defineConfig({
markdown: {
rehypePlugins: [[
rehypeSmartLinks,
{
wrapperTemplate: (node, linkType) => {
let icon;
if (linkType === 'internal') {
// Internal link - right arrow
icon = h('svg', {
class: 'w-3.5 h-3.5',
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: 'M13 7l5 5m0 0l-5 5m5-5H6'
})
]);
// Add icon to the end of the link
node.children.push(icon);
node.properties.className = [
'inline-flex',
'items-center',
'gap-1',
'text-blue-600',
'hover:text-blue-800'
];
}
else if (linkType === 'external') {
// External link - external link icon
icon = h('svg', {
class: 'w-3.5 h-3.5',
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'
})
]);
// Add icon to the end of the link
node.children.push(icon);
node.properties.className = [
'inline-flex',
'items-center',
'gap-1',
'text-purple-600',
'hover:text-purple-800'
];
}
else if (linkType === 'broken') {
// Broken link - warning icon
icon = h('svg', {
class: 'w-3.5 h-3.5',
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: 'M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z'
})
]);
// Add icon to the beginning of the link
node.children = [icon, ...node.children];
node.properties.className = [
'inline-flex',
'items-center',
'gap-1',
'text-red-600',
'hover:text-red-800'
];
}
return node;
}
}
]]
}
});
Animated Links with Tailwind
Create eye-catching animations for your links using Tailwind’s transition utilities:
Animated Links with Tailwind
// astro.config.mjs
import { defineConfig } from 'astro/config';
import rehypeSmartLinks from 'rehype-smart-links';
import { h } from 'hastscript';
export default defineConfig({
markdown: {
rehypePlugins: [[
rehypeSmartLinks,
{
wrapperTemplate: (node, linkType) => {
if (linkType === 'internal') {
// Store original text
const originalText = node.children[0]?.value || 'Link';
// Create underline animation effect
node.children = [
h('span', { class: 'relative z-10' }, [originalText]),
h('span', {
class: 'absolute bottom-0 left-0 w-full h-0.5 bg-blue-600 origin-left transform scale-x-0 transition-transform duration-300 ease-out group-hover:scale-x-100'
})
];
node.properties.className = [
'relative',
'text-blue-600',
'font-medium'
];
}
else if (linkType === 'external') {
// Arrow icon with animation
const icon = h('svg', {
class: 'w-3.5 h-3.5 transform transition-transform duration-300 group-hover:translate-x-1',
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: 'M14 5l7 7m0 0l-7 7m7-7H3'
})
]);
node.children.push(icon);
node.properties.className = [
'group',
'inline-flex',
'items-center',
'gap-1',
'text-purple-600',
'font-medium'
];
}
else if (linkType === 'broken') {
// Warning icon with animation
const text = node.children[0]?.value || 'Broken Link';
const icon = h('svg', {
class: 'inline-block w-4 h-4 ml-1 animate-pulse',
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: 'M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z'
})
]);
node.children = [
h('span', { class: 'opacity-75' }, [text]),
icon
];
node.properties.className = [
'relative',
'text-red-600',
'font-medium',
'cursor-not-allowed'
];
}
return node;
}
}
]]
}
});
Tailwind Card Links
Create card-style links for more prominent navigation options:
Tailwind Card Links
Internal Link
External Link
Broken Link
// astro.config.mjs
import { defineConfig } from 'astro/config';
import rehypeSmartLinks from 'rehype-smart-links';
import { h } from 'hastscript';
export default defineConfig({
markdown: {
rehypePlugins: [[
rehypeSmartLinks,
{
wrapperTemplate: (node, linkType) => {
const originalText = node.children[0]?.value || 'Link';
let icon, container, title, description;
if (linkType === 'internal') {
// Info icon for internal link
icon = h('svg', {
class: 'w-5 h-5 text-blue-600',
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: 'M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z'
})
]);
container = h('div', { class: 'flex-shrink-0 bg-blue-100 p-2 rounded-lg' }, [icon]);
title = h('h3', { class: 'text-sm font-medium text-gray-900' }, [originalText]);
description = h('p', { class: 'text-xs text-gray-500' }, ['Learn more about our project']);
node.properties.className = [
'block',
'p-4',
'bg-white',
'border',
'border-gray-200',
'rounded-lg',
'shadow-sm',
'hover:bg-gray-50',
'transition-colors',
'duration-200'
];
}
else if (linkType === 'external') {
// External link icon
icon = h('svg', {
class: 'w-5 h-5 text-purple-600',
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'
})
]);
container = h('div', { class: 'flex-shrink-0 bg-purple-100 p-2 rounded-lg' }, [icon]);
title = h('h3', { class: 'text-sm font-medium text-gray-900' }, [originalText]);
description = h('p', { class: 'text-xs text-gray-500' }, ['View source code (opens in new tab)']);
node.properties.className = [
'block',
'p-4',
'bg-white',
'border',
'border-gray-200',
'rounded-lg',
'shadow-sm',
'hover:bg-gray-50',
'transition-colors',
'duration-200'
];
}
else if (linkType === 'broken') {
// Warning icon for broken link
icon = h('svg', {
class: 'w-5 h-5 text-red-600',
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: 'M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z'
})
]);
container = h('div', { class: 'flex-shrink-0 bg-red-100 p-2 rounded-lg' }, [icon]);
title = h('h3', { class: 'text-sm font-medium text-gray-900 line-through' }, [originalText]);
description = h('p', { class: 'text-xs text-red-500' }, ['This page does not exist']);
node.properties.className = [
'block',
'p-4',
'bg-white',
'border',
'border-gray-200',
'rounded-lg',
'shadow-sm',
'opacity-75',
'cursor-not-allowed'
];
}
// Create content container
const content = h('div', { class: 'ml-4' }, [title, description]);
// Create flexible layout
const flex = h('div', { class: 'flex items-center' }, [container, content]);
// Update node children
node.children = [flex];
return node;
}
}
]]
}
});
Dark Mode Support
Create links that work well in both light and dark modes with Tailwind’s dark mode utilities:
Dark Mode Compatible Links
// tailwind.config.js
module.exports = {
darkMode: 'class', // or 'media' if you prefer system preferences
// other tailwind configuration...
}
// astro.config.mjs
import { defineConfig } from 'astro/config';
import rehypeSmartLinks from 'rehype-smart-links';
export default defineConfig({
markdown: {
rehypePlugins: [[
rehypeSmartLinks,
{
className: {
internal: 'text-blue-600 dark:text-blue-400 hover:text-blue-800 dark:hover:text-blue-300 underline',
external: 'text-purple-600 dark:text-purple-400 hover:text-purple-800 dark:hover:text-purple-300 underline',
broken: 'text-red-600 dark:text-red-400 hover:text-red-800 dark:hover:text-red-300 line-through'
}
}
]]
}
});
Tailwind for Tooltips
Use Tailwind to create custom tooltips for your links:
Tailwind Tooltip Links
Internal Link
About PageInternal page
External Link
GitHubOpens in new tab
Broken Link
Broken LinkLink not found
// astro.config.mjs
import { defineConfig } from 'astro/config';
import rehypeSmartLinks from 'rehype-smart-links';
import { h } from 'hastscript';
export default defineConfig({
markdown: {
rehypePlugins: [[
rehypeSmartLinks,
{
wrapperTemplate: (node, linkType) => {
// Set link styles based on type
if (linkType === 'internal') {
node.properties.className = ['text-blue-600', 'hover:text-blue-800', 'group-hover:underline'];
// Create tooltip
const tooltip = h('span', {
class: 'invisible group-hover:visible absolute left-1/2 -translate-x-1/2 -bottom-9 w-28 px-2 py-1 bg-gray-900 rounded-md text-center text-white text-xs after:content-[""] after:absolute after:left-1/2 after:-top-1 after:-translate-x-1/2 after:border-4 after:border-transparent after:border-b-gray-900'
}, ['Internal page']);
// Wrap in container with tooltip
return h('span', { class: 'group relative' }, [node, tooltip]);
}
else if (linkType === 'external') {
node.properties.className = ['text-purple-600', 'hover:text-purple-800', 'group-hover:underline'];
// Create tooltip
const tooltip = h('span', {
class: 'invisible group-hover:visible absolute left-1/2 -translate-x-1/2 -bottom-9 w-32 px-2 py-1 bg-gray-900 rounded-md text-center text-white text-xs after:content-[""] after:absolute after:left-1/2 after:-top-1 after:-translate-x-1/2 after:border-4 after:border-transparent after:border-b-gray-900'
}, ['Opens in new tab']);
// Wrap in container with tooltip
return h('span', { class: 'group relative' }, [node, tooltip]);
}
else if (linkType === 'broken') {
node.properties.className = ['text-red-600', 'hover:text-red-800', 'line-through', 'cursor-not-allowed'];
// Create tooltip
const tooltip = h('span', {
class: 'invisible group-hover:visible absolute left-1/2 -translate-x-1/2 -bottom-9 w-28 px-2 py-1 bg-gray-900 rounded-md text-center text-white text-xs after:content-[""] after:absolute after:left-1/2 after:-top-1 after:-translate-x-1/2 after:border-4 after:border-transparent after:border-b-gray-900'
}, ['Link not found']);
// Wrap in container with tooltip
return h('span', { class: 'group relative' }, [node, tooltip]);
}
return node;
}
}
]]
}
});
Next Steps
Explore more styling options:
- Basic Demo - Simple link styling examples
- DaisyUI Styles - Using DaisyUI components with rehype-smart-links
- Custom CSS - Advanced CSS styling techniques