All rules

Sheath rule

a11y-no-heading-inside-button

Heading elements should not be nested inside buttons.
Package
Core
Default severity
error by default
Auto-fix
Manual fix

#Why

Screen readers offer a list of a page's headings as a way to jump around it. A heading inside a button puts a control in that list, so someone navigating by heading encounters a button instead of the start of a document section.

The button also stops being announced as a plain control, since its accessible name now arrives wrapped in heading semantics.

#Examples

#Bad

<!-- Heading inside button -->
<button>
<h2>Click Here</h2>
</button>
<!-- Nested heading inside button -->
<button>
<div>
<h3>Submit Form</h3>
</div>
</button>
<!-- Element with role="button" containing heading -->
<div role="button">
<h4>Action</h4>
</div>

#Good

<!-- Use span for styled text inside buttons -->
<button>
<span class="button-title">Click Here</span>
</button>
<!-- Plain text in button -->
<button>Submit Form</button>
<!-- Styled text without heading semantics -->
<button>
<span class="large-text">Action</span>
</button>
<!-- Heading before button -->
<h2>Actions</h2>
<button>Click Here</button>

#Notes

  • Use CSS to style button text instead of headings
  • <span> elements can be styled to look like headings without semantic issues
  • Elements with role="button" are included
  • The same principle applies to links - avoid headings inside <a> tags

#References

#Related Rules