Skip to content

add MDX heading permalinks for tutorial pages#1403

Open
syam-bukkuru wants to merge 1 commit into
processing:mainfrom
syam-bukkuru:feature/tutorial-heading-permalinks
Open

add MDX heading permalinks for tutorial pages#1403
syam-bukkuru wants to merge 1 commit into
processing:mainfrom
syam-bukkuru:feature/tutorial-heading-permalinks

Conversation

@syam-bukkuru
Copy link
Copy Markdown

@syam-bukkuru syam-bukkuru commented May 19, 2026

Summary

Adds MDX heading permalinks for tutorial pages using component overrides in TutorialLayout.astro.

Closes #1398

Changes

  • Introduced reusable HeadingPermalink component (Preact)
  • Overrode h1–h6 in tutorial MDX rendering only
  • Preserved Astro-generated heading IDs
  • Made entire heading clickable (links to #fragment)
  • Added improved hover UX:
    • # indicator appears on hover/focus (left side, subtle color)
    • heading text underlines on hover
  • Scoped styles under .tutorials .rendered-markdown
  • Avoided nested anchor issues

Demo

Short demo showing heading hover, permalink visibility, and fragment navigation:
https://github.com/user-attachments/assets/ab1f6c54-a9a5-423d-860e-360aec349cd9

Testing

  • npm run check passes (no errors)
  • npm run build succeeds
  • Verified:
    • hovering a heading shows # indicator
    • clicking heading updates URL fragment
    • direct #fragment navigation scrolls correctly
    • headings without IDs do not break
    • headings with inline links do not create nested anchors

Notes

  • Service worker 404 seen in dev console is unrelated to this change
  • No changes to routes, schemas, or global markdown behavior

@@ -1,4 +1,4 @@
@import "/styles/variables.scss";
@use "/styles/variables" as *;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was this to fix anything in particular? Ideally this change should not need to affect how we import other files, or update the package lock.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Those changes were to address local Sass deprecation warnings about @import being phased out in favor of @use. I updated them while testing.

type HeadingProps = HTMLAttributes<HTMLHeadingElement> & {
as: HeadingTag;
children?: ComponentChildren;
id?: string;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For my understanding, what passes this in? Since it seems to be implicit, we may want to add a comment to explain it.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MDX passes these props automatically when rendering headings. Astro already injects things like id, children, etc. into the heading components, so this just forwards them into our custom component.

aria-label="Link to this section"
>
<span class="heading-permalink__text">{children}</span>
<span class="heading-permalink__icon">#</span>
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not huge, but possibly this could be done with just one <a> tag as before without <span> children if we add the # via CSS? something like

.heading-permalink::after: {
  content: '#';
  display: inline;
  /* ...etc */
}

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah I thought about that, but since we’re making the whole heading a link, if the heading text contains inline links it could create nested anchors. that’s why I split it out earlier.

but yeah using ::after for # still makes sense.

img: FreeRatioImage,
pre: PreProxy,
a: LinkWrapper,
h1: HeadingPermalinkH1,
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While the tutorial layout is the main thing I had in mind when raising the issue, are there other pages that would benefit from this too? e.g. probably pages with the contributor docs should also have it. Put another way, should this be the default, maybe with other pages opting out if need be? @ksen0 let me know if you have thoughts there!

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I scoped it to tutorials first since that’s what the issue mentioned, but this could definitely be useful for other MDX pages like contributor docs too.

I wasn’t sure if it should be global by default or opt-in per layout, so I kept it limited for now. happy to extend it or move it to a shared layout if that’s preferred.

@davepagurek
Copy link
Copy Markdown
Collaborator

Thanks for working on this, your screen recording looks like what I was imagining for this feature! Left some comments, let me know what you think.

@ksen0
Copy link
Copy Markdown
Member

ksen0 commented May 21, 2026

Thanks for working on this! Please link the issue in the PR description

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add permalinks for headings in tutorials

3 participants