p-as-heading

Text styled to look like a heading should probably be a real heading

manualWCAG 1.3.1 (A)confidence: lowseverity: minorperceivable

Flags short <p> and <div> elements whose text is all bold and rendered at >=18px, for manual review of whether a real heading element should be used instead.

Applies to. <p> elements, and <div> elements that hold only text and inline markup, whose visible text is short (<=120 char) and non-empty, and in which every visible piece of text is bold (computed font-weight >= 700, however it got there: on the element itself, a <strong>/<b> or a styled <span>) and rendered at >=18px. Visible text is the text that is rendered (not display:none, [hidden] or visibility:hidden) and not screen-reader-only. Text that is all inside controls (a widget's or a <label>'s own text) is left out.

Expectation. Text styled to visually read as a heading (bold, larger-than-body size, short) should be marked up with a real heading element (<h1>-<h6> or role="heading") so its structural role is programmatically determinable, the same 1.3.1 concern as any other "structure conveyed through presentation only" issue.

What a finding reports.

  • reasonCode: HEADING_LIKE_NUMBER when the text is only a number (digits with spacing and punctuation: "2024", "No 12" is not one), HEADING_LIKE_LINK when it is all inside one link, so a report can set either kind aside as a group; otherwise BOLD_LARGE_PARAGRAPH for a <p> and BOLD_LARGE_DIV for a <div>. All are asked about.
  • fontSizePx: the font size of the text as drawn, in CSS pixels (the computed size times CSS zoom, an SVG transform or what font-size-adjust scales the font by), the smallest one when the pieces differ, against the 18px threshold.

These data.details fields help to read and reproduce a finding. Apart from reasonCode and the few fields Output schema names as stable, they are not a stable contract: a field may be renamed or dropped in a minor release, so don’t build on them.

Examples

can't tell
<style>.fakeHeading { font-weight: bold; font-size: 22px; }</style>
<p class="fakeHeading">Section Title</p>

Bold, heading-sized, and short — visually a heading, but marked up as a plain <p> with no heading semantics.

n/a
<p>Just a normal paragraph of body text that is not bold at all.</p>

Normal weight and size; nothing visually suggests a heading.

can't tell
<div style="font-size: 24px"><span style="font-weight: bold">Our team</span></div>

A <div> holding only text is checked like a <p>, and the bold can come from a styled <span> inside it. A <div> that holds other blocks, and text inside a button, label or table header, is not asked about.

How to check

When this rule can’t decide, it reports cantTell and leaves the question to a person. Each question it can ask is listed here under its reason code, with the steps to answer it. A finding carries the same steps as howToCheck, in the scan’s language. See Output schema.

BOLD_LARGE_DIV

  1. Find the bold, large block of text the report names and look at it in the page.
  2. Decide whether it introduces the content that follows it, as a section title does, or is just emphasis, a callout or a value.
  3. If it acts as a title, check in the Accessibility pane of the developer tools, or with a screen reader's heading list, whether it is exposed as a heading.

Pass. The text is not a section title (emphasis, a quote, a price or a statistic), or it is marked up as a heading (h1 to h6 or role="heading").

Fail. The text visually titles a section but is not a heading, so its structure is shown only by style, which fails WCAG 1.3.1 (F2).

BOLD_LARGE_PARAGRAPH

  1. Find the bold, large paragraph the report names and look at it in the page.
  2. Decide whether it introduces the content that follows it, as a section title does, or is just emphasis, a callout or a value.
  3. If it acts as a title, check in the Accessibility pane of the developer tools, or with a screen reader's heading list, whether it is exposed as a heading.

Pass. The text is not a section title (emphasis, a quote, a price or a statistic), or it is marked up as a heading (h1 to h6 or role="heading").

Fail. The text visually titles a section but is not a heading, so its structure is shown only by style, which fails WCAG 1.3.1 (F2).

  1. Find the bold, large linked text the report names and look at it in the page.
  2. Decide whether it introduces the content that follows it, as a section title does, or is just emphasis, a callout or a value.
  3. If it acts as a title, check in the Accessibility pane of the developer tools, or with a screen reader's heading list, whether it is exposed as a heading.

Pass. The text is not a section title (emphasis, a quote, a price or a statistic), or it is marked up as a heading (h1 to h6 or role="heading").

Fail. The text visually titles a section but is not a heading, so its structure is shown only by style, which fails WCAG 1.3.1 (F2).

HEADING_LIKE_NUMBER

  1. Find the bold, large number (such as a year) the report names and look at it in the page.
  2. Decide whether it introduces the content that follows it, as a section title does, or is just emphasis, a callout or a value.
  3. If it acts as a title, check in the Accessibility pane of the developer tools, or with a screen reader's heading list, whether it is exposed as a heading.

Pass. The text is not a section title (emphasis, a quote, a price or a statistic), or it is marked up as a heading (h1 to h6 or role="heading").

Fail. The text visually titles a section but is not a heading, so its structure is shown only by style, which fails WCAG 1.3.1 (F2).

View source