Back to blog

GitHub-Style Heading Links in Astro

3 min read

Overview

I wanted the headings in my Astro Markdown site to behave like GitHub’s:
hover to reveal a link icon for deep-linking to that heading.

After reading rehype-autolink-headings’ docs on using hastscript,
I realized I could replicate the effect with some tailwindcss magic.

Before and after

Here’s how it looked before and after adding the configuration.

Without any changes, hovering over a heading does nothing. There’s no visual cue that it’s linkable.

Screenshot of Astro heading without hover link

Now when you hover over a heading, a subtle link icon appears.
Clicking it jumps directly to that heading’s URL.

Screenshot of Astro heading with hover link icon

How it works

Example configuration

astro.config.ts
import { defineConfig } from "astro/config";
import { h } from "hastscript";
import rehypeSlug from "rehype-slug";
import rehypeAutolinkHeadings from "rehype-autolink-headings";
const autoLinkHeadingOpts = {
behavior: "wrap",
content: [
h("span", {
"aria-hidden": "true",
"class":
"icon-[lucide--link] absolute left-0 top-1/2 -translate-y-1/2 " +
"opacity-0 group-hover:opacity-100 transition-opacity duration-150 " +
"text-base-content/50 h-[1em] w-[1em]",
}),
],
properties: {
className: "group relative block pl-[1.5em] -ml-[1.5em]",
tabindex: "-1",
},
};
export default defineConfig({
markdown: {
gfm: true,
rehypePlugins: [rehypeSlug, [rehypeAutolinkHeadings, autoLinkHeadingOpts]],
},
});

Breaking down the configuration

The autoLinkHeadingOpts object controls how rehype-autolink-headings wraps and styles your headings.

content

content: [
h("span", {
"aria-hidden": "true",
class:
"icon-[lucide--link] absolute left-0 top-1/2 -translate-y-1/2 " +
"opacity-0 group-hover:opacity-100 transition-opacity duration-150 " +
"text-base-content/50 h-[1em] w-[1em]",
}),
],

properties

properties: {
className: "group relative block pl-[1.5em] -ml-[1.5em]",
tabindex: "-1",
},

Note on icons

The icon-[lucide--link] class comes from Iconify with the Tailwind 4 plugin.

Installing the plugin

Terminal window
bun add -D @iconify/tailwind4 @iconify-json/lucide
globals.css
@plugin "@iconify/tailwind4";

Using a different icon

Swap lucide--link for any other Lucide icon or from another installed Iconify collection. Or, use your own icon setup such as SVGs, React components, or any approach you prefer.

Wrapping up

With just a couple of rehype plugins, a sprinkle of hastscript, and some Tailwind magic, you can make your Astro headings more interactive, just like GitHub’s.

Gif of Astro heading with hover link icon

Let's Discuss

Questions or feedback? Send me an email.

Last updated on

Back to blog