@@ -239,12 +239,27 @@ export async function renderReadmeHtml(
239239 const collectedLinks : PlaygroundLink [ ] = [ ]
240240 const seenUrls = new Set < string > ( )
241241
242- // Shift heading levels down by 2 for semantic correctness
242+ // Track heading hierarchy to ensure sequential order for accessibility
243243 // Page h1 = package name, h2 = "Readme" section heading
244- // So README h1 → h3, h2 → h4, etc. (capped at h6)
245- // But keep visual styling via data-level attribute
244+ // So README starts at h3, and we ensure no levels are skipped
245+ // Visual styling preserved via data-level attribute (original depth)
246+ let lastSemanticLevel = 2 // Start after h2 (the "Readme" section heading)
246247 renderer . heading = function ( { tokens, depth } : Tokens . Heading ) {
247- const semanticLevel = Math . min ( depth + 2 , 6 )
248+ // Calculate the target semantic level based on document structure
249+ // Start at h3 (since page h1 + section h2 already exist)
250+ // But ensure we never skip levels - can only go down by 1 or stay same/go up
251+ let semanticLevel : number
252+ if ( depth === 1 ) {
253+ // README h1 always becomes h3
254+ semanticLevel = 3
255+ } else {
256+ // For deeper levels, ensure sequential order
257+ // Don't allow jumping more than 1 level deeper than previous
258+ const maxAllowed = Math . min ( lastSemanticLevel + 1 , 6 )
259+ semanticLevel = Math . min ( depth + 2 , maxAllowed )
260+ }
261+
262+ lastSemanticLevel = semanticLevel
248263 const text = this . parser . parseInline ( tokens )
249264 return `<h${ semanticLevel } data-level="${ depth } ">${ text } </h${ semanticLevel } >\n`
250265 }
0 commit comments