
Company News
Socket Named Top Sales Organization by RepVue
Socket won two 2026 Reppy Awards from RepVue, ranking in the top 5% of all sales orgs. AE Alexandra Lister shares what it's like to grow a sales career here.
semantic-heading-hierarchy
Advanced tools
A JavaScript library that automatically invisibly corrects improper heading hierarchies for better accessibility. Used for user or admin edited content where the developer doesn't have 100% direct control over the content.
A JavaScript library that automatically corrects improper heading hierarchies for better accessibility and SEO while preserving original visual styling to prevent layout flash.
Many websites have incorrect heading hierarchies that harm accessibility and SEO. Common issues include:
This library automatically fixes these issues by:
hs-X classes to maintain original stylingnpm install semantic-heading-hierarchy
Or via CDN:
<script src="https://unpkg.com/semantic-heading-hierarchy@latest/dist/index.js"></script>
Important: You must implement your own CSS for hs-2 through hs-6 classes to maintain visual consistency:
/* Style hs-X classes to match their original heading appearance */
h1, .hs-1 {
/* Your H1 styles here */
}
h2, .hs-2 {
/* Your H2 styles here */
}
h3, .hs-3 {
/* Your H3 styles here */
}
h4, .hs-4 {
/* Your H4 styles here */
}
h5, .hs-5 {
/* Your H5 styles here */
}
h6, .hs-6 {
/* Your H6 styles here */
}
import SemanticHeadingHierarchy from 'semantic-heading-hierarchy';
// Fix headings in entire document
SemanticHeadingHierarchy.fix();
// Fix headings in specific container
SemanticHeadingHierarchy.fix('.main-content');
// Enable detailed logging
SemanticHeadingHierarchy.fix('.content', { logResults: true });
// Convert additional H1s to H2s (for pages with multiple H1s)
SemanticHeadingHierarchy.fix('.content', { forceSingleH1: true });
// Use custom CSS class prefix
SemanticHeadingHierarchy.fix('.content', { classPrefix: 'fs-' });
// Available on window object
window.SemanticHeadingHierarchy.fix('.main-content');
SemanticHeadingHierarchy.fix('.content', {
logResults: true, // Show detailed console output
classPrefix: 'hs-', // CSS class prefix (default: 'hs-')
forceSingleH1: false // Convert additional H1s to H2s (default: false)
});
Before:
<article>
<h1>Main Article Title</h1>
<h4>Introduction</h4> <!-- Skips H2, H3 levels -->
<h6>Key Points</h6> <!-- Skips H5 level -->
<h2>Conclusion</h2> <!-- Jumps back to H2 -->
</article>
After:
<article>
<h1>Main Article Title</h1> <!-- Untouched -->
<h2 class="hs-4" data-prev-heading="4">Introduction</h2> <!-- Corrected, styled as H4 -->
<h3 class="hs-6" data-prev-heading="6">Key Points</h3> <!-- Corrected, styled as H6 -->
<h2>Conclusion</h2> <!-- Already correct -->
</article>
You can customize the class prefix to match your existing CSS framework:
// Default behavior (includes dash)
SemanticHeadingHierarchy.fix('.content'); // Creates hs-4, hs-5, etc.
// Custom prefix with dash
SemanticHeadingHierarchy.fix('.content', { classPrefix: 'fs-' }); // Creates fs-4, fs-5, etc.
// Custom prefix without dash
SemanticHeadingHierarchy.fix('.content', { classPrefix: 'h' }); // Creates h4, h5, etc.
One of the coolest features is the global localStorage-based debugging system that lets you enable detailed logging across your entire site without modifying any code!
Enable debug mode instantly - Run this in your browser console:
// Turn on detailed logging for ALL fix calls
SemanticHeadingHierarchy.logging.enable();
Turn off debug mode:
SemanticHeadingHierarchy.logging.disable();
When debug mode is enabled, you'll see detailed console output like this:
✅ Detailed heading healing logging ENABLED globally
Found 5 heading(s) to process after H1
Will change H4 → H2 (will add hs-4 class)
Will change H6 → H3 (will add hs-6 class)
Replaced H4 with H2, added hs-4 class
Replaced H6 with H3, added hs-6 class
Heading structure fix complete. Modified 2 heading(s)
You can also control logging programmatically:
// Enable logging globally
SemanticHeadingHierarchy.logging.enable();
// Disable logging globally
SemanticHeadingHierarchy.logging.disable();
// Clear override (use function parameters)
SemanticHeadingHierarchy.logging.clear();
// Check current status
SemanticHeadingHierarchy.logging.status();
The library prevents visual layout disruption by adding styling classes before changing the element tag:
hs-X class is added to the original elementBefore:
<h1>Main Title</h1>
<h4>Section Title</h4> <!-- Wrong level, but styled as h4 -->
After:
<h1>Main Title</h1>
<h2 class="hs-4" data-prev-heading="4">Section Title</h2>
The hs-4 class (heading-style-4) allows you to maintain the original H4 visual styling while using the semantically correct H2 tag.
This library does NOT create H1 elements - it requires them to exist.
The H1 tag is the most important heading on your page and should be carefully chosen by developers, not automatically generated. Here's why:
We understand that sometimes you inherit websites or work with CMSs where you can't control the entire page structure.
If you have multiple H1 elements (which violates accessibility standards), the library will use the first H1 as the main heading and warn you about the additional ones:
⚠️ Found 2 additional H1 element(s) after the first H1. These will be ignored. Consider using the forceSingleH1 option to convert them to H2 elements.
You can use the forceSingleH1 option to automatically convert additional H1s to H2s:
SemanticHeadingHierarchy.fix('.content', { forceSingleH1: true });
If you have headings before the H1 (like in navigation or headers), the library will still work - it will process headings after the H1 but will show you a console warning:
⚠️ Found 2 heading(s) before H1: h2, h3. These headings will be ignored for accessibility compliance. Consider restructuring your HTML to place all content headings after the main H1.
These warnings are always shown regardless of your logging settings because they're important for accessibility compliance.
Before (Multiple H1s - accessibility violation):
<article>
<h1>Main Article Title</h1> <!-- First H1 - will be preserved -->
<h3>Section</h3> <!-- Skips H2 -->
<h1>Another Main Title</h1> <!-- Additional H1 - accessibility violation -->
<h4>Subsection</h4> <!-- Skips H3 -->
<h1>Yet Another Title</h1> <!-- Additional H1 - accessibility violation -->
</article>
After (with forceSingleH1: true):
<article>
<h1>Main Article Title</h1> <!-- First H1 preserved -->
<h2 class="hs-3" data-prev-heading="3">Section</h2> <!-- H3 → H2 -->
<h2 class="hs-1" data-prev-heading="1">Another Main Title</h2> <!-- H1 → H2 -->
<h3 class="hs-4" data-prev-heading="4">Subsection</h3> <!-- H4 → H3 -->
<h2 class="hs-1" data-prev-heading="1">Yet Another Title</h2> <!-- H1 → H2 -->
</article>
// Process only the main content area
SemanticHeadingHierarchy.fix('.main-content');
// Process specific article
SemanticHeadingHierarchy.fix('#article-123');
// Process with logging
SemanticHeadingHierarchy.fix('.content-area', { logResults: true });
SemanticHeadingHierarchy.fix(containerOrSelector, options)Parameters:
containerOrSelector (string|Element, optional): CSS selector or DOM element to process. Defaults to document.bodyoptions (boolean|FixOptions, optional): Options object or boolean for backwards compatibility
options.logResults (boolean, optional): Enable detailed console logging. Defaults to falseoptions.classPrefix (string, optional): Custom prefix for styling classes. Defaults to 'hs-'options.forceSingleH1 (boolean, optional): Convert additional H1 elements to H2 elements. Defaults to falseRequirements:
Selector Requirements:
Returns: void
SemanticHeadingHierarchy.loggingMethods:
SemanticHeadingHierarchy.logging.enable(): Enable detailed logging for all fix calls via localStorageSemanticHeadingHierarchy.logging.disable(): Disable detailed logging for all fix calls via localStorageSemanticHeadingHierarchy.logging.clear(): Clear localStorage override, returns to using function parametersSemanticHeadingHierarchy.logging.status(): Get the current logging status from localStorageThe library intelligently handles headings within lists:
<!-- Multi-item list - headings ignored -->
<ul>
<li><h4>Item 1</h4></li>
<li><h4>Item 2</h4></li>
<li><h4>Item 3</h4></li>
</ul>
<!-- Single-item list - heading processed -->
<ul>
<li><h6>Special Feature</h6></li> <!-- Will become h3 with hs-6 class -->
</ul>
This package uses html-validate with the heading-level rule for accessibility validation in our test suite. This ensures that our heading corrections actually meet real-world accessibility standards.
Array.from, Element.closest)Contributions are welcome! Here's how to get started:
Clone the repository:
git clone https://github.com/sitefinitysteve/semantic-heading-hierarchy.git
cd semantic-heading-hierarchy
Install dependencies:
npm install
Run the development commands:
# Run tests
npm test
# Run tests in watch mode
npm test -- --watch
# Run specific test file
npm test -- test/healer.test.js
# Type check
npm run typecheck
# Build the package
npm run build
# Lint the code
npm run lint
# Format the code
npm run format
semantic-heading-hierarchy/
├── src/
│ ├── index.ts # Main entry point
│ ├── core.ts # Core healing logic
│ ├── logging.ts # Logging functionality
│ └── types.ts # TypeScript interfaces
├── test/
│ ├── healer.test.js # Basic functionality tests
│ ├── rigorous-healer.test.js # Comprehensive tests
│ ├── complex-fixtures.test.js # Real-world scenarios
│ └── fixtures/ # Test HTML fixtures
├── dist/ # Built files (generated)
├── package.json # Package configuration
├── tsconfig.json # TypeScript configuration
└── README.md # This file
The project uses Vitest for testing and html-validate for accessibility validation:
Create a feature branch:
git checkout -b feature/your-feature-name
Make your changes and add tests:
Run the test suite:
npm test
Build and verify:
npm run build
npm run typecheck
Submit a pull request:
MIT License - see LICENSE file for details.
Made with ❤️ for better web accessibility
FAQs
A JavaScript library that automatically invisibly corrects improper heading hierarchies for better accessibility. Used for user or admin edited content where the developer doesn't have 100% direct control over the content.
We found that semantic-heading-hierarchy demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Company News
Socket won two 2026 Reppy Awards from RepVue, ranking in the top 5% of all sales orgs. AE Alexandra Lister shares what it's like to grow a sales career here.

Security News
NIST will stop enriching most CVEs under a new risk-based model, narrowing the NVD's scope as vulnerability submissions continue to surge.

Company News
/Security News
Socket is an initial recipient of OpenAI's Cybersecurity Grant Program, which commits $10M in API credits to defenders securing open source software.