Skip to content

fix(www): make mdx h2 id generation handle nested heading content - #1016

Closed
zigzagdev wants to merge 1 commit into
magicuidesign:mainfrom
zigzagdev:fix/www-mdx-heading-id
Closed

zigzagdev wants to merge 1 commit into
magicuidesign:mainfrom
zigzagdev:fix/www-mdx-heading-id

Conversation

@zigzagdev

@zigzagdev zigzagdev commented Oct 3, 2026 •

Copy link
Copy Markdown
Contributor

Description

The h2 heading id was built with props.children?.toString(), which returns "[object Object]" whenever a heading contains nested markdown like bold or code, breaking the anchor id and any deep link or table-of-contents jump to that heading.
It also only stripped spaces, apostrophes, and question marks, leaving other punctuation (:, ,, (, ), /) in the generated id.
This PR walks the children tree to extract plain text first, then slugifies it properly.

Changes

  • Add getHeadingText() to recursively extract plain text from a heading's React children tree
  • Add slugifyHeading() to normalize that text into a safe, predictable anchor id (lowercase, strip non-alphanumeric characters, collapse whitespace to hyphens)
  • Use both in the h2 MDX component's id generation instead of props.children?.toString()

Motivation

At least two live blog posts have h2 headings wrapped in bold, which rendered their anchor id as the literal string object-object, breaking deep links and table-of-contents navigation to those sections.
Headings with other punctuation (colons, parentheses, commas, slashes) — 66 across docs/blog — also produced invalid or unpredictable ids.
So, this fix makes heading id generation robust regardless of inline formatting.

Breaking Changes

None

Screenshots

Device / Browser / Viewport:

Before After

Not applicable

Checklist

  • pnpm check passes locally
  • pnpm build passes locally
  • pnpm build:registry was run and the generated files are committed (if you changed registry/ or config/site.ts — CI verifies this on every PR)
  • PR title follows Conventional Commits (e.g., feat(marquee): add reverse prop)

The h2 heading id was built with props.children?.toString(), which
returns "[object Object]" whenever a heading contains nested markdown
like **bold** or `code`, breaking the anchor id and any deep link or
table-of-contents jump to that heading. It also only stripped spaces,
apostrophes, and question marks, leaving other punctuation (":", ",",
"(", ")", "/") in the generated id.

Walk the children tree to collect plain text first, then slugify it
properly (lowercase, strip non-alphanumeric characters, collapse to
hyphens) so the id is always a valid, predictable anchor regardless
of what inline formatting the heading uses.
@vercel

vercel Bot commented Oct 3, 2026

Copy link
Copy Markdown

@zigzagdev is attempting to deploy a commit to the product-studio Team on Vercel.

A member of the Team first needs to authorize it.

@Yeom-JinHo
Yeom-JinHo self-requested a review October 5, 2026 08:15
@Yeom-JinHo

Copy link
Copy Markdown
Member

Thanks @zigzagdev! Closing since this doesn't reproduce: fumadocs' remarkHeading already sets heading ids, and {...props} is spread after id so the custom id is never applied (prod renders e.g. the-benefits-of-using-a-react-ui-component-library).

@Yeom-JinHo Yeom-JinHo closed this Oct 5, 2026
@zigzagdev
zigzagdev deleted the fix/www-mdx-heading-id branch October 5, 2026 10:38
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.

2 participants