Accessibility / Structure & Headings / Heading Structure Validator

The Heading Structure Validator bookmarklet analyzes the page's heading hierarchy to ensure proper semantic structure. Finds all headings (h1-h6), validates that heading levels follow a logical order without skipping levels (e.g., jumping from h1 to h3), detects empty headings, warns about multiple h1 headings (which should generally be avoided), and displays an interactive outline view showing the heading hierarchy. Click any heading in the panel to scroll to and highlight it on the page. Run again to remove.

WCAG SC 1.3.1: Info and Relationships
Run Heading Structure Validator

Test run or drag to
bookmarklets bar to install

javascript:%21function()%7B%22use%20strict%22%3Btry%7Bconst%20n%3Ddocument.getElementById(%22heading-validator-host%22)%3Bn%26%26n.remove()%3Bconst%20e%3Ddocument.getElementById(%22hsv-highlight-style%22)%3Be%26%26e.remove()%3Bconst%20t%3Ddocument.createElement(%22div%22)%3Bt.id%3D%22heading-validator-host%22%2Ct.style.cssText%3D%22position%3Afixed%3Btop%3A10px%3Bright%3A10px%3Bz-index%3A999999%3Bwidth%3A450px%3Bmax-height%3A85vh%3B%22%2Cdocument.body.appendChild(t)%3Bconst%20s%3Dt.attachShadow(%7Bmode%3A%22open%22%7D)%2Ci%3Ddocument.createElement(%22style%22)%3Bi.textContent%3D%22%5Cn%20%20%20%20%20%20*%20%7B%20box-sizing%3A%20border-box%3B%20%7D%5Cn%20%20%20%20%20%20.hsv-panel%20%7B%5Cn%20%20%20%20%20%20%20%20font-family%3A%20-apple-system%2C%20BlinkMacSystemFont%2C%20%27Segoe%20UI%27%2C%20Roboto%2C%20sans-serif%3B%5Cn%20%20%20%20%20%20%20%20background%3A%20white%3B%5Cn%20%20%20%20%20%20%20%20border%3A%202px%20solid%20%23333%3B%5Cn%20%20%20%20%20%20%20%20border-radius%3A%208px%3B%5Cn%20%20%20%20%20%20%20%20box-shadow%3A%200%204px%2020px%20rgba(0%2C0%2C0%2C0.3)%3B%5Cn%20%20%20%20%20%20%20%20display%3A%20flex%3B%5Cn%20%20%20%20%20%20%20%20flex-direction%3A%20column%3B%5Cn%20%20%20%20%20%20%20%20max-height%3A%2085vh%3B%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20.hsv-header%20%7B%5Cn%20%20%20%20%20%20%20%20background%3A%20%23333%3B%5Cn%20%20%20%20%20%20%20%20color%3A%20white%3B%5Cn%20%20%20%20%20%20%20%20padding%3A%2012px%2016px%3B%5Cn%20%20%20%20%20%20%20%20display%3A%20flex%3B%5Cn%20%20%20%20%20%20%20%20justify-content%3A%20space-between%3B%5Cn%20%20%20%20%20%20%20%20align-items%3A%20center%3B%5Cn%20%20%20%20%20%20%20%20border-radius%3A%206px%206px%200%200%3B%5Cn%20%20%20%20%20%20%20%20flex-shrink%3A%200%3B%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20.hsv-title%20%7B%5Cn%20%20%20%20%20%20%20%20font-weight%3A%20600%3B%5Cn%20%20%20%20%20%20%20%20font-size%3A%200.875rem%3B%5Cn%20%20%20%20%20%20%20%20margin%3A%200%3B%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20.hsv-close%20%7B%5Cn%20%20%20%20%20%20%20%20background%3A%20none%3B%5Cn%20%20%20%20%20%20%20%20border%3A%20none%3B%5Cn%20%20%20%20%20%20%20%20color%3A%20white%3B%5Cn%20%20%20%20%20%20%20%20font-size%3A%201.25rem%3B%5Cn%20%20%20%20%20%20%20%20cursor%3A%20pointer%3B%5Cn%20%20%20%20%20%20%20%20padding%3A%200%3B%5Cn%20%20%20%20%20%20%20%20width%3A%2028px%3B%5Cn%20%20%20%20%20%20%20%20height%3A%2028px%3B%5Cn%20%20%20%20%20%20%20%20display%3A%20flex%3B%5Cn%20%20%20%20%20%20%20%20align-items%3A%20center%3B%5Cn%20%20%20%20%20%20%20%20justify-content%3A%20center%3B%5Cn%20%20%20%20%20%20%20%20border-radius%3A%204px%3B%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20.hsv-close%3Ahover%20%7B%5Cn%20%20%20%20%20%20%20%20background%3A%20rgba(255%2C255%2C255%2C0.2)%3B%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20.hsv-content%20%7B%5Cn%20%20%20%20%20%20%20%20padding%3A%2016px%3B%5Cn%20%20%20%20%20%20%20%20overflow-y%3A%20auto%3B%5Cn%20%20%20%20%20%20%20%20flex%3A%201%3B%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20.hsv-summary%20%7B%5Cn%20%20%20%20%20%20%20%20background%3A%20%23f5f5f5%3B%5Cn%20%20%20%20%20%20%20%20padding%3A%2012px%3B%5Cn%20%20%20%20%20%20%20%20border-radius%3A%206px%3B%5Cn%20%20%20%20%20%20%20%20margin-bottom%3A%2016px%3B%5Cn%20%20%20%20%20%20%20%20font-size%3A%200.8125rem%3B%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20.hsv-summary%20strong%20%7B%5Cn%20%20%20%20%20%20%20%20display%3A%20block%3B%5Cn%20%20%20%20%20%20%20%20margin-bottom%3A%208px%3B%5Cn%20%20%20%20%20%20%20%20font-size%3A%200.875rem%3B%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20.hsv-stat%20%7B%5Cn%20%20%20%20%20%20%20%20display%3A%20inline-block%3B%5Cn%20%20%20%20%20%20%20%20margin-right%3A%2016px%3B%5Cn%20%20%20%20%20%20%20%20margin-bottom%3A%204px%3B%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20.hsv-stat.pass%20%7B%20color%3A%20%2328a745%3B%20%7D%5Cn%20%20%20%20%20%20.hsv-stat.fail%20%7B%20color%3A%20%23dc3545%3B%20%7D%5Cn%20%20%20%20%20%20.hsv-outline%20%7B%5Cn%20%20%20%20%20%20%20%20background%3A%20white%3B%5Cn%20%20%20%20%20%20%20%20border%3A%201px%20solid%20%23ddd%3B%5Cn%20%20%20%20%20%20%20%20border-radius%3A%206px%3B%5Cn%20%20%20%20%20%20%20%20padding%3A%2012px%3B%5Cn%20%20%20%20%20%20%20%20margin-top%3A%2012px%3B%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20.hsv-outline-title%20%7B%5Cn%20%20%20%20%20%20%20%20font-weight%3A%20600%3B%5Cn%20%20%20%20%20%20%20%20font-size%3A%200.875rem%3B%5Cn%20%20%20%20%20%20%20%20margin-bottom%3A%2012px%3B%5Cn%20%20%20%20%20%20%20%20padding-bottom%3A%208px%3B%5Cn%20%20%20%20%20%20%20%20border-bottom%3A%201px%20solid%20%23ddd%3B%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20.hsv-heading-item%20%7B%5Cn%20%20%20%20%20%20%20%20padding%3A%206px%208px%3B%5Cn%20%20%20%20%20%20%20%20margin%3A%202px%200%3B%5Cn%20%20%20%20%20%20%20%20border-radius%3A%204px%3B%5Cn%20%20%20%20%20%20%20%20cursor%3A%20pointer%3B%5Cn%20%20%20%20%20%20%20%20transition%3A%20background%200.2s%3B%5Cn%20%20%20%20%20%20%20%20font-size%3A%200.8125rem%3B%5Cn%20%20%20%20%20%20%20%20display%3A%20flex%3B%5Cn%20%20%20%20%20%20%20%20align-items%3A%20center%3B%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20.hsv-heading-item%3Ahover%20%7B%5Cn%20%20%20%20%20%20%20%20background%3A%20%23f0f0f0%3B%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20.hsv-heading-item.error%20%7B%5Cn%20%20%20%20%20%20%20%20background%3A%20%23ffe6e6%3B%5Cn%20%20%20%20%20%20%20%20border-left%3A%203px%20solid%20%23dc3545%3B%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20.hsv-heading-item.warning%20%7B%5Cn%20%20%20%20%20%20%20%20background%3A%20%23fff3cd%3B%5Cn%20%20%20%20%20%20%20%20border-left%3A%203px%20solid%20%23ffc107%3B%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20.hsv-heading-item.valid%20%7B%5Cn%20%20%20%20%20%20%20%20border-left%3A%203px%20solid%20%2328a745%3B%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20.hsv-level%20%7B%5Cn%20%20%20%20%20%20%20%20font-weight%3A%20700%3B%5Cn%20%20%20%20%20%20%20%20min-width%3A%2035px%3B%5Cn%20%20%20%20%20%20%20%20color%3A%20%23666%3B%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20.hsv-text%20%7B%5Cn%20%20%20%20%20%20%20%20flex%3A%201%3B%5Cn%20%20%20%20%20%20%20%20white-space%3A%20nowrap%3B%5Cn%20%20%20%20%20%20%20%20overflow%3A%20hidden%3B%5Cn%20%20%20%20%20%20%20%20text-overflow%3A%20ellipsis%3B%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20.hsv-issue%20%7B%5Cn%20%20%20%20%20%20%20%20color%3A%20%23dc3545%3B%5Cn%20%20%20%20%20%20%20%20font-size%3A%200.6875rem%3B%5Cn%20%20%20%20%20%20%20%20margin-left%3A%208px%3B%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20.hsv-warning%20%7B%5Cn%20%20%20%20%20%20%20%20color%3A%20%23856404%3B%5Cn%20%20%20%20%20%20%20%20font-size%3A%200.6875rem%3B%5Cn%20%20%20%20%20%20%20%20margin-left%3A%208px%3B%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20.hsv-indent%20%7B%5Cn%20%20%20%20%20%20%20%20display%3A%20inline-block%3B%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20.hsv-highlight%20%7B%5Cn%20%20%20%20%20%20%20%20outline%3A%203px%20solid%20%23007bff%20%21important%3B%5Cn%20%20%20%20%20%20%20%20outline-offset%3A%202px%20%21important%3B%5Cn%20%20%20%20%20%20%20%20background%3A%20rgba(0%2C123%2C255%2C0.1)%20%21important%3B%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20.hsv-empty-section%20%7B%5Cn%20%20%20%20%20%20%20%20color%3A%20%23999%3B%5Cn%20%20%20%20%20%20%20%20font-style%3A%20italic%3B%5Cn%20%20%20%20%20%20%20%20padding%3A%2012px%3B%5Cn%20%20%20%20%20%20%20%20text-align%3A%20center%3B%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%22%2Cs.appendChild(i)%3Bconst%20o%3Ddocument.createElement(%22div%22)%3Bo.className%3D%22hsv-panel%22%2Cs.appendChild(o)%3Bconst%20a%3DArray.from(document.querySelectorAll(%22h1%2C%20h2%2C%20h3%2C%20h4%2C%20h5%2C%20h6%22))%2Cr%3D%7Bh1%3A0%2Ch2%3A0%2Ch3%3A0%2Ch4%3A0%2Ch5%3A0%2Ch6%3A0%7D%2Ch%3D%5B%5D%3Blet%20l%3D0%3Bconst%20d%3D%5B%5D%3Ba.forEach((n%2Ce)%3D%3E%7Bconst%20t%3DparseInt(n.tagName%5B1%5D)%3Br%5B%22h%22%2Bt%5D%2B%2B%3Bconst%20s%3D%7Belement%3An%2Clevel%3At%2Ctext%3An.textContent.trim().substring(0%2C80)%2CfullText%3An.textContent.trim()%2Cindex%3Ae%2ChasIssue%3A%211%2ChasWarning%3A%211%2Cissues%3A%5B%5D%7D%3Bif(l%3E0%26%26t%3El%2B1)%7Bconst%20n%3D%5B%5D%3Bfor(let%20e%3Dl%2B1%3Be%3Ct%3Be%2B%2B)n.push(%22h%22%2Be)%3Bconst%20e%3D%60Skipped%20level(s)%3A%20%24%7Bn.join(%22%2C%20%22)%7D%60%3Bs.hasIssue%3D%210%2Cs.issues.push(e)%2Ch.push(%7Btype%3A%22error%22%2Cmessage%3A%60H%24%7Bt%7D%20%22%24%7Bs.text%7D%22%20-%20%24%7Be%7D%60%7D)%7D1%3D%3D%3Dt%26%26r.h1%3E1%26%26(s.hasWarning%3D%210%2Cs.issues.push(%22Multiple%20h1%20headings%20found%22)%2C2%3D%3D%3Dr.h1%26%26h.push(%7Btype%3A%22warning%22%2Cmessage%3A%22Multiple%20h1%20headings%20detected%22%7D))%2Cn.textContent.trim()%7C%7C(s.hasIssue%3D%210%2Cs.issues.push(%22Empty%20heading%22)%2Ch.push(%7Btype%3A%22error%22%2Cmessage%3A%60H%24%7Bt%7D%20is%20empty%60%7D))%2Cd.push(s)%2Cl%3Dt%7D)%3Bconst%20p%3Dr.h1%3E0%3Bp%7C%7Ch.push(%7Btype%3A%22warning%22%2Cmessage%3A%22No%20h1%20heading%20found%22%7D)%3Bconst%20c%3Dh.filter(n%3D%3E%22error%22%3D%3D%3Dn.type).length%2Cg%3Dh.filter(n%3D%3E%22warning%22%3D%3D%3Dn.type).length%3Blet%20v%3D%60%5Cn%20%20%20%20%20%20%3Cdiv%20class%3D%22hsv-header%22%3E%5Cn%20%20%20%20%20%20%20%20%3Ch2%20class%3D%22hsv-title%22%3EHeading%20Structure%20Validator%3C%2Fh2%3E%5Cn%20%20%20%20%20%20%20%20%3Cbutton%20class%3D%22hsv-close%22%20aria-label%3D%22Close%22%20onclick%3D%22document.getElementById(%27heading-validator-host%27).remove()%3Bdocument.getElementById(%27hsv-highlight-style%27).remove()%22%3E%26times%3B%3C%2Fbutton%3E%5Cn%20%20%20%20%20%20%3C%2Fdiv%3E%5Cn%20%20%20%20%20%20%3Cdiv%20class%3D%22hsv-content%22%3E%5Cn%20%20%20%20%20%20%20%20%3Cdiv%20class%3D%22hsv-summary%22%3E%5Cn%20%20%20%20%20%20%20%20%20%20%3Cstrong%3ESummary%3A%3C%2Fstrong%3E%5Cn%20%20%20%20%20%20%20%20%20%20%3Cdiv%20class%3D%22hsv-stat%20%24%7Bp%3F%22pass%22%3A%22fail%22%7D%22%3E%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%24%7Bp%3F%22%5Cu2713%22%3A%22%5Cu2717%22%7D%20h1%3A%20%24%7Br.h1%7D%5Cn%20%20%20%20%20%20%20%20%20%20%3C%2Fdiv%3E%5Cn%20%20%20%20%20%20%20%20%20%20%3Cdiv%20class%3D%22hsv-stat%22%3Eh2%3A%20%24%7Br.h2%7D%3C%2Fdiv%3E%5Cn%20%20%20%20%20%20%20%20%20%20%3Cdiv%20class%3D%22hsv-stat%22%3Eh3%3A%20%24%7Br.h3%7D%3C%2Fdiv%3E%5Cn%20%20%20%20%20%20%20%20%20%20%3Cdiv%20class%3D%22hsv-stat%22%3Eh4%3A%20%24%7Br.h4%7D%3C%2Fdiv%3E%5Cn%20%20%20%20%20%20%20%20%20%20%3Cdiv%20class%3D%22hsv-stat%22%3Eh5%3A%20%24%7Br.h5%7D%3C%2Fdiv%3E%5Cn%20%20%20%20%20%20%20%20%20%20%3Cdiv%20class%3D%22hsv-stat%22%3Eh6%3A%20%24%7Br.h6%7D%3C%2Fdiv%3E%5Cn%20%20%20%20%20%20%20%20%20%20%3Cdiv%20style%3D%22margin-top%3A8px%3Bpadding-top%3A8px%3Bborder-top%3A1px%20solid%20%23ddd%22%3E%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%3Cspan%20class%3D%22hsv-stat%20%24%7B0%3D%3D%3Dc%3F%22pass%22%3A%22fail%22%7D%22%3E%24%7Bc%7D%20error(s)%3C%2Fspan%3E%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%3Cspan%20class%3D%22hsv-stat%20%24%7B0%3D%3D%3Dg%3F%22pass%22%3A%22fail%22%7D%22%3E%24%7Bg%7D%20warning(s)%3C%2Fspan%3E%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%3Cspan%20class%3D%22hsv-stat%22%3ETotal%3A%20%24%7Ba.length%7D%20headings%3C%2Fspan%3E%5Cn%20%20%20%20%20%20%20%20%20%20%3C%2Fdiv%3E%5Cn%20%20%20%20%20%20%20%20%3C%2Fdiv%3E%5Cn%20%20%20%20%60%3Ba.length%3E0%3F(v%2B%3D%27%5Cn%20%20%20%20%20%20%20%20%3Cdiv%20class%3D%22hsv-outline%22%3E%5Cn%20%20%20%20%20%20%20%20%20%20%3Cdiv%20class%3D%22hsv-outline-title%22%3EHeading%20Outline%3C%2Fdiv%3E%5Cn%20%20%20%20%20%20%27%2Cd.forEach((n%2Ce)%3D%3E%7Bconst%20t%3D16*(n.level-1)%2Cs%3Dn.hasIssue%3F%22error%22%3An.hasWarning%3F%22warning%22%3A%22valid%22%3Bv%2B%3D%60%5Cn%20%20%20%20%20%20%20%20%20%20%3Cdiv%20class%3D%22hsv-heading-item%20%24%7Bs%7D%22%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20data-heading-index%3D%22%24%7Be%7D%22%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20onclick%3D%22scrollToHeading(%24%7Be%7D)%22%3E%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%3Cspan%20class%3D%22hsv-level%22%3EH%24%7Bn.level%7D%3C%2Fspan%3E%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%3Cspan%20class%3D%22hsv-text%22%20style%3D%22margin-left%3A%24%7Bt%7Dpx%22%3E%24%7Bn.text%7C%7C%22(empty)%22%7D%3C%2Fspan%3E%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%24%7Bn.issues.map(e%3D%3E%60%3Cspan%20class%3D%22%24%7Bn.hasIssue%3F%22hsv-issue%22%3A%22hsv-warning%22%7D%22%3E%24%7Be%7D%3C%2Fspan%3E%60).join(%22%22)%7D%5Cn%20%20%20%20%20%20%20%20%20%20%3C%2Fdiv%3E%5Cn%20%20%20%20%20%20%20%20%60%7D)%2Cv%2B%3D%22%3C%2Fdiv%3E%22)%3Av%2B%3D%27%3Cdiv%20class%3D%22hsv-empty-section%22%3ENo%20headings%20found%20on%20this%20page.%3C%2Fdiv%3E%27%2Cv%2B%3D%22%3C%2Fdiv%3E%22%2Co.innerHTML%3Dv%3Bconst%20m%3Ddocument.createElement(%22style%22)%3Bm.id%3D%22hsv-highlight-style%22%2Cm.textContent%3D%22.hsv-highlight%20%7B%20outline%3A%203px%20solid%20%23007bff%20%21important%3B%20outline-offset%3A%202px%20%21important%3B%20background%3A%20rgba(0%2C123%2C255%2C0.1)%20%21important%3B%20%7D%22%2Cdocument.head.appendChild(m)%2Cwindow.hsvHeadings%3Dd.map(n%3D%3En.element)%2Cwindow.scrollToHeading%3Dfunction(n)%7Bdocument.querySelectorAll(%22.hsv-highlight%22).forEach(n%3D%3En.classList.remove(%22hsv-highlight%22))%3Bconst%20e%3Dwindow.hsvHeadings%5Bn%5D%3Be%26%26(e.classList.add(%22hsv-highlight%22)%2Ce.scrollIntoView(%7Bbehavior%3A%22smooth%22%2Cblock%3A%22center%22%7D)%2CsetTimeout(()%3D%3Ee.classList.remove(%22hsv-highlight%22)%2C2e3))%7D%2Cconsole.log(%22%5BHeading%20Structure%20Validator%5D%20-%20Analysis%20complete%22)%7Dcatch(n)%7Balert(%22Bookmarklet%20Error%3A%20%22%2Bn.message)%7D%7D()%2Cconsole.log(%22%5CnSource%3A%20https%3A%2F%2Fgithub.com%2Fpattespatte%2Fpublic-bookmarklets%2F%5CnBookmarklet%20name%3A%20Heading%20Structure%20Validator%5Cn%22)%3B
← Back to all bookmarklets