DEV Community

Cover image for Semantica11y - Semantic HTML for Everyone
Mark Steadman
Mark Steadman

Posted on

Semantica11y - Semantic HTML for Everyone

Modern web development has habit of using <div>, <span> and other non-native elements and then slapping a coat of ARIA roles on them to ensure they are "accessible'. The result is a tangled web of ARIA that is used to cover a foundation of "DIV soup".

I built Semantica11y to help fix that.

Semantica11y is a small, focused rules engine that analyzes your application and highlights places where semantic HTML should be used instead of ARIA-heavy or non-semantic patterns. It’s not Axe-core, its not a WCAG violation checker, it’s simply a tool that helps you write cleaner, sustainable, and more accessible markup from the start.

Why I Created Semantica11y

After years of reviewing sites for accessibility and getting asked questions on how to fix accessibility issues, I kept seeing the same patterns.

Using ARIA instead of semantic or native elements:


<div role="button"> instead of <button>

Enter fullscreen mode Exit fullscreen mode

Overriding native label for buttons completely:


<button aria-label="Insurance Information">Continue </button>

Enter fullscreen mode Exit fullscreen mode

Completely missing key landmarks for webpages:


<body>
  <header></header>
  <main></main>
  <footer></footer>
</body>

Enter fullscreen mode Exit fullscreen mode

ARIA attributes used to recreate native behavior that HTML already provides out of the box. These aren’t violations but instead are missed opportunities.

I wanted a tool that:

  • Encourages developers to use semantic HTML first

  • Helps testers identify semantic gaps in UI components

  • Integrates cleanly into Playwright, CI pipelines, and local dev workflows

  • Educates developers on WHY semantic/native HTML matters.

Using Semantica11y

Semantica11y is published on npm, so installation is straightforward:


npm install semantica11y

Enter fullscreen mode Exit fullscreen mode

It is designed to run against rendered HTML, which most integration testing libraries such as Playwright allow you to be able to test against.

Here’s a simple Playwright example:


const { test, expect } = require('@playwright/test');
const semantica11y = import('semantica11y');

test('scans a live page with the published semantica11y package', async ({ page }, testInfo) => {
  const { Analyzer, exportTextReport, formatConsoleReport } = await semantica11y;
  const analyzer = new Analyzer();

  await page.goto('https://www.normalil.gov/', { waitUntil: 'domcontentloaded' });

  const results = await analyzer.analyzeHTML(
    await page.content(),
    page.url()
  );

  console.log(formatConsoleReport(results, { colors: false }));

  const reportPath = testInfo.outputPath('semantica11y-report.txt');
  await exportTextReport(results, reportPath, { colors: false });
  console.log(`Semantica11y text report written to: ${reportPath}`);

  expect(results.summary.errors).toBe(0);
  expect(results.summary.warnings).toBe(0);
});

});

Enter fullscreen mode Exit fullscreen mode

The Results

When your test cases with Semantica11y you can either console out the results or get a text format of the results put to a specific folder.

An example of the output looks like the following below:

Output report with the following: Total number of issues, the report is broken out into errors, warnings, and suggestions

The results are broken up into errors, warnings and suggestions.

Where to Learn More and Contribute

If you to explore the project more in depth, contribute, or follow for more updates, go here: https://github.com/Steady5063/Semantica11y

Top comments (0)