dequelabs / dequelabs/axe-core

False positive: p-as-heading fires on <p role="heading" aria-level="n">

Open Beginner friendly
#5,283 2 comments 0 reactions 0 assignees View on GitHub
fix good first issue rules
Dominant language
JavaScript
Stars
7.5k
Forks
933
Avg merge
2d 23h
Merged PRs (30d)
17

Description

### Product

axe-core

### Product Version

4.12.1

### Latest Version

- [x] I have tested the issue with the latest version of the product

### Issue Description

#### Expectation
p-as-heading should not report a violation for a `

` element that carries an explicit role="heading" with aria-level. Such an element is exposed as a heading in the accessibility tree, and the pattern is [ARIA12](https://www.w3.org/WAI/WCAG22/Techniques/aria/ARIA12), a documented sufficient technique for SC 1.3.1. The element should not be matched by the rule at all (expected outcome: inapplicable).

#### Actual
The element is reported as a serious violation — `"Heading elements should be used instead of styled

elements"` — regardless of the role or aria-level present on it.

#### How to Reproduce

```html


Section title


Body copy that follows the heading.



```

```js
axe.run('#root', { runOnly: ['p-as-heading'] })
.then(results => console.log(results.violations));
```

Result: one violation, `target #root > p:nth-child(1)`.

#### Additional context
lib/rules/p-as-heading-matches.js checks only three things — non-empty text, fewer than two sentence terminators, and the presence of a following non-empty `

` sibling. Neither the matches function nor p-as-heading-evaluate calls getRole / getExplicitRole, so an explicit role="heading" can never exclude the element. Evaluation then proceeds purely on computed style (weight / italic / size ratio against the next paragraph).

Contributor guide

Open the contributing guide

Research direction

Start with lib/rules/p-as-heading-matches.js and the p-as-heading-evaluate logic described in the issue; review how explicit roles are obtained elsewhere in the rule set. Verify the reproduced HTML with axe.run using the p-as-heading rule, then add coverage for p[role="heading"][aria-level] and confirm it is reported as inapplicable while the following paragraph case remains covered.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript
Domain
accessibility, testing
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
78/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.