Modern web development has a habit of using <div>, <span>, and other non-native elements and then applying ARIA roles to make them accessible. The result can be a tangled web of ARIA covering 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 is not axe-core or a WCAG violation checker. It is 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 answering questions about fixing accessibility issues, I kept seeing the same patterns.

Using ARIA instead of semantic or native elements:

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

Overriding a button’s native label completely:

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

Completely missing key landmarks for web pages:

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

ARIA attributes are often used to recreate native behavior that HTML already provides. These are not always violations, but they 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 development workflows
  • Educates developers on why semantic and native HTML matter

Using Semantica11y

Semantica11y is published on npm, so installation is straightforward:

npm install semantica11y

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

Here is 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 });

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

The Results

When your test cases use Semantica11y, you can print the results to the console or save a text report to a specific folder.

A Semantica11y output report showing the total number of issues organized into errors, warnings, and suggestions.

The results are separated into errors, warnings, and suggestions.

Where to Learn More and Contribute

To explore the project in more depth, contribute, or follow future updates, visit the Semantica11y project on GitHub.