( Perceivable / WCAG 1.3.1 )

Definition list structure is invalid

ModerateLevel AWCAG 1.3.1 — Info and Relationships

What is this issue?

A <dl> element has one or more direct children that aren’t <dt>, <dd>, or a <div> used purely to group a <dt>/<dd> pair: commonly a <p> holding the term and a <span> holding the definition, styled to look right but built with the wrong tags. HTML’s definition list model expects <dl> to contain nothing else at the top level.

This is the “wrong children inside the container” failure. A separate, related failure covers <dt> or <dd> elements that exist with no <dl> wrapping them at all. This rule is specifically about what’s allowed inside an existing <dl>.

Why does this matter?

A screen reader uses <dl>, <dt>, and <dd> structure to announce a “term” role for the label and a “definition” role for the value that belongs to it, so a user hears the pairing as a connected unit rather than two unrelated pieces of text. When a <dl> holds <p> and <span> elements instead, that structural pairing doesn’t exist: the browser has no defined way to associate the “term” text with its “definition” text, because neither element carries the role that pairing depends on.

The practical effect is a glossary, FAQ, or spec sheet that reads as a flat stream of unconnected sentences. A sighted user still sees the visual pairing from layout (bold term, indented definition underneath), but a screen reader user gets none of that spatial cue and has to guess which definition belongs to which term from context alone.

Who is affected?

  • Screen reader users: hear term and definition text as disconnected, unrelated content instead of a paired unit, and have to infer the pairing from reading order and content alone.
  • Cognitive disabilities: users who rely on the term/definition structure to scan a glossary or FAQ efficiently lose that scanning shortcut when the pairing isn’t structurally announced.

What users experience

Rosa uses NVDA on Windows to look up a term in a software company’s glossary page, built as a <dl> where each entry is actually a <p> for the term followed by a <span> for the definition, styled with CSS to look indented. NVDA reads through the page as a flat sequence of paragraphs with no term or definition role announced at any point. Rosa can still read every word, but she loses the ability to jump directly between terms (the navigation shortcut a properly structured <dl> would give her) and has to read the whole glossary from the top to find the entry she needs.

How do I fix it?

Use <dt> for every term and <dd> for every definition, as direct children of <dl> (or grouped in a <div> wrapping each pair). This works because <dt> and <dd> are the only elements that carry the term and definition roles a screen reader looks for: no amount of CSS styling on other tags recreates that role.

If you need to wrap each term-definition pair in a container for styling (adding a border, background, or spacing around each entry as a unit), wrap them in a <div> that sits as a direct child of <dl>, holding the <dt> and its <dd> (or <dd> elements, if a term has more than one definition) inside it. HTML explicitly permits this grouping pattern, so it doesn’t break the structure the way an unrelated tag like <p> or <li> would.

Code Examples

Before
<dl>
  <p>API</p>
  <span>Application Programming Interface</span>
</dl>
After
<!-- Method 1: dt/dd as direct children -->
<dl>
  <dt>API</dt>
  <dd>Application Programming Interface</dd>
</dl>

<!-- Method 2: grouped in a div, useful for styling each pair as a unit -->
<dl>
  <div class="glossary-entry">
    <dt>API</dt>
    <dd>Application Programming Interface</dd>
  </div>
</dl>

Both fixes replace the generic <p>/<span> pair with <dt>/<dd>, which is the change that actually restores the term/definition roles. The grouping <div> in Method 2 is optional: it changes nothing about the accessible structure, since HTML explicitly allows it as a wrapper, and it only exists to give each entry a stylable container.

Common Mistakes

Mistake: “The definition list looks right visually, with the term above the definition, so the markup must be fine.” CSS can make any pair of elements look visually indented and paired; that says nothing about whether a screen reader can compute the same relationship from the DOM. Visual layout and accessible structure are entirely independent; only <dt>/<dd> inside <dl> produce the actual term/definition roles.

Mistake: “I need a heading above each definition, so I used h4 instead of dt.” A heading element and a term element serve different purposes: <h4> puts an entry into the page’s heading-navigation hierarchy, which usually isn’t what a glossary entry needs, and it isn’t a valid <dl> direct child at all. Use <dt> for the term itself; if you also want entries to be heading-navigable, that’s a sign the content might be better structured as sections with real headings instead of a definition list.

Mistake: “Div wrapping breaks the dl structure, so I need to keep dt and dd as direct flat children even for styling.” The opposite is true: HTML’s definition-list model explicitly permits a <div> to group one <dt>/<dd> pair (or a <dt> with multiple <dd> elements) as a direct child of <dl>. Grouping divs are a fully valid, commonly used pattern, not a workaround.

How RedFlag Detects This

Automated: axe-core rule, runs on every scan. RedFlag calls axe-core’s definition-list rule as part of every scan, restricted to the WCAG 2.0/2.1/2.2 A and AA rule set. The rule inspects every <dl> element and flags any whose direct children include anything other than <dt>, <dd>, <script>, <template>, or a <div> used to group <dt>/<dd> pairs.

False negative: axe-core confirms the structural pattern is valid; it can’t judge whether a <dt>’s definition actually belongs to it. A <dl> where the term and definition text are swapped, or where a <dd> describes the wrong <dt> entirely, passes this structural check even though the content pairing is wrong. False positive: none typical for this check, since verifying each direct child’s tag name against the small allowed set is a binary structural comparison. Manual step: for any <dl> on the page, read through the term/definition pairs with a screen reader and confirm each <dd> genuinely defines the <dt> immediately before it, since structural validity alone doesn’t guarantee correct pairing.

Manual Testing

  1. Open the page in Chrome or Firefox with NVDA or JAWS running on Windows, or VoiceOver on macOS.
  2. Navigate into any glossary, FAQ, or spec-sheet section built with a <dl>.
  3. Listen for a “term” role announced before each label and a “definition” (or “description”) role announced before each value.
  4. If the term and definition are read as plain, unrelated text with no role announced, inspect the markup in browser dev tools to confirm whether <dt>/<dd> are actually being used.
  5. Confirm each definition you hear is announced immediately after (and clearly paired with) the correct term, not a different one.

1.3.1 Info and Relationships: Information, structure, and relationships conveyed through presentation must also be available programmatically. A term visually paired with its definition through layout alone only satisfies this criterion once the pairing is also expressed with the correct <dt>/<dd> markup.

Definition list item used outside a dl element is the mirror-image failure: instead of a <dl> containing the wrong children, it’s <dt> or <dd> elements existing with no <dl> wrapping them at all.

List contains an element other than li and List items are not contained within a list element are the same pair of failures (wrong children inside the container, and container-less items outside it) applied to <ul>/<ol>/<li> structures instead of <dl>/<dt>/<dd>.

References

Frequently asked questions

Can I wrap a dt/dd pair in a div inside a dl?

Yes. HTML explicitly allows a div to group one or more dt and dd elements as a direct child of dl, which is useful for styling a term-definition pair as a unit. The div is the only grouping element allowed there alongside dt and dd themselves.

Is a definition list the same thing as a glossary?

A glossary is one common use of a definition list, but dl is not limited to glossaries. It also fits any term-value or label-value pairing, such as a metadata table, a FAQ laid out as question and answer, or a product spec sheet.

Can one dt have more than one dd underneath it?

Yes. A single term can have multiple dd elements, which is useful for a term with several definitions or several related values, such as one dt for a product name followed by separate dd elements for color, size, and price.

Does axe-core check whether the term and definition text actually make sense together?

No. Automated tools verify the structural rule that only dt, dd, and grouping div elements exist as direct children of dl; they cannot judge whether the definition text under a given term is accurate or relevant.

Should I use dl for a simple two-column layout that has nothing to do with terms and definitions?

No. Using dl purely for its default visual layout misuses the element semantic meaning, since a screen reader announces it as a term-description structure regardless of your intent. Use a table or styled div layout instead when the content is not genuinely a set of term-value pairs.