Skip to content

Definition lists and abbreviations

Terms and descriptions, abbreviation definitions and the document levels that may declare them.

Generated from resources/examples/edge-cases.md and resources/examples/core.md - edit the cases there, not here. Each case links the conformance fixture it produces.

Abbreviation matches on word boundaries only

1 conformance fixture

A defined abbreviation is expanded only as a whole word — it is not substituted inside a longer word.

carve
*[HTML]: HyperText Markup Language

HTML and XHTMLish.
html
<p><abbr title="HyperText Markup Language">HTML</abbr> and XHTMLish.</p>

Abbreviation definition interrupts a paragraph

1 conformance fixture

An abbreviation definition is an invisible construct (§10): on the line directly after prose it is consumed and applied, with no blank line needed.

carve
The HTML spec is long.
*[HTML]: HyperText Markup Language
html
<p>The <abbr title="HyperText Markup Language">HTML</abbr> spec is long.</p>

Abbreviation definition separator must be a space

1 conformance fixture

Abbreviation definitions follow the rule too: *[label]: must be followed by a literal space. A tab keeps the line as a paragraph and no abbreviation is registered.

carve
*[HTML]:	Hyper

The HTML
html
<p>*[HTML]:	Hyper</p>
<p>The HTML</p>

Definition list as a first-class block opener

4 conformance fixtures

A :: term definition-list opener is a block opener like every other (quote, heading, fence, table) under the content-column rule (PART 9 §24 C3): it interrupts an open list item at column 0, and nests at the item's content column. The two-line :: /: marker is recognized by look-ahead; only the :: term line opens the block.

At the content column, the definition list nests inside the item.

carve
- one
  :: term
  :  def
html
<ul>
  <li>one
    <dl>
      <dt>term</dt>
      <dd>def</dd>
    </dl>
  </li>
</ul>

At column 0 (below the content column), it interrupts: the list ends and the definition list parses at document level.

carve
- one
:: term
:  def
html
<ul>
  <li>one</li>
</ul>
<dl>
  <dt>term</dt>
  <dd>def</dd>
</dl>

Below the content column but not at column 0, it folds in as lazy item text.

carve
- one
 :: term
 :  def
html
<ul>
  <li>one
:: term
:  def</li>
</ul>

A blank line before a nested definition list keeps the outer item tight (§17), like any other nested sub-block.

carve
- one

  :: t
  :  d
html
<ul>
  <li>one
    <dl>
      <dt>t</dt>
      <dd>d</dd>
    </dl>
  </li>
</ul>

Abbreviation title escapes its markup characters

1 conformance fixture

An abbreviation's expansion becomes the title attribute, so &, <, > and " in it are entity-escaped like any attribute value.

carve
*[HTML]: Hyper & Text < Markup > "quoted"

The HTML spec.
html
<p>The <abbr title="Hyper &amp; Text &lt; Markup &gt; &quot;quoted&quot;">HTML</abbr> spec.</p>

Under-indented definition attaches, over-indented definition folds

3 conformance fixtures

A : def line is a lenient definition-list entry (PART 9 §24 C3): it attaches as a fresh <dd> to its open :: term when its column is at or below the term's, even under the item's content column. Only a definition line indented above the term folds into the term text as a lazy continuation.

Under-indented (below the content column, still above column 0): the definition attaches.

carve
- one
  :: term
 :  def
html
<ul>
  <li>one
    <dl>
      <dt>term</dt>
      <dd>def</dd>
    </dl>
  </li>
</ul>

At column 0, the definition still attaches: the : marker is a lenient exception to the column-0 interrupt rule, so it does not end the item and orphan the definition.

carve
- one
  :: term
:  def
html
<ul>
  <li>one
    <dl>
      <dt>term</dt>
      <dd>def</dd>
    </dl>
  </li>
</ul>

Over-indented (above the term): the line folds into the term, preserving its over-indent whitespace.

carve
- one
  :: term
   :  def
html
<ul>
  <li>one
    <dl>
      <dt>term
 :  def</dt>
    </dl>
  </li>
</ul>

Wrapped definition term continuation below the content column strips leading whitespace

2 conformance fixtures

A :: term line inside a list item may be continued by a wrapped line. When that continuation sits below the item content column it is a lazy continuation, so - like a lazy paragraph or blockquote continuation - its leading whitespace is stripped before it folds into the <dt>. (A continuation above the content column instead folds with its residual indent preserved; a continuation at or above the content column is dedented rather than stripped.)

At column 1, one below the content column 2: the leading space is stripped before the fold.

carve
- one
  :: term
 wrapped
html
<ul>
  <li>one
    <dl>
      <dt>term
wrapped</dt>
    </dl>
  </li>
</ul>

At column 0, flush left: the continuation still folds into the term, byte-identically.

carve
- one
  :: term
wrapped
html
<ul>
  <li>one
    <dl>
      <dt>term
wrapped</dt>
    </dl>
  </li>
</ul>

Two abbreviation definitions

1 conformance fixture

Nothing about the second definition is special - it is here because a document with TWO of them is what tells the engines apart. The HTML says nothing about how the definitions were spelled, so a formatter that joined them differently stayed invisible until the canonical-Carve target was compared across engines (carve-php#682).

carve
*[HTML]: HyperText Markup Language
*[CSS]: Cascading Style Sheets

HTML and CSS.
html
<p><abbr title="HyperText Markup Language">HTML</abbr> and <abbr title="Cascading Style Sheets">CSS</abbr>.</p>

An abbreviation definition is recognized only at document level

1 conformance fixture

*[TERM]: expansion defines an abbreviation only as a direct child of the document. Inside a block quote, a list item or a div the line is ordinary paragraph text: it defines nothing and it is preserved as written. An abbreviation is the only definition kind with no marker at the use site, so a definition carried in quoted material would otherwise rewrite every occurrence of its term in the quoting document.

carve
> *[HTML]: Hyper Text

The HTML spec.
html
<blockquote><p>*[HTML]: Hyper Text</p></blockquote>
<p>The HTML spec.</p>

A list item does not define an abbreviation either

1 conformance fixture

The same rule holds for every container, not just the block quote: the definition line stays visible text and expands nothing.

carve
- *[HTML]: Hyper Text

The HTML spec.
html
<ul>
  <li>*[HTML]: Hyper Text</li>
</ul>
<p>The HTML spec.</p>

A div does not define an abbreviation either

1 conformance fixture

The rule names three containers - a block quote, a list item and a div - and the first two were pinned while the third was not. A div is the one of the three that renders its children unchanged, so a definition inside it is the case where the line looks most like a document-level one, and the use below it still gets no <abbr>.

carve
:::
*[HTML]: Hyper Text

The HTML spec.
:::
html
<div>
  <p>*[HTML]: Hyper Text</p>
  <p>The HTML spec.</p>
</div>

A definition below every content column folds as text

1 conformance fixture

A definition is not block-shaped, but §24 C3's "every other line" covers it too: below every open content column it folds into the item paragraph as literal text and registers nothing, so a reference to it elsewhere stays literal. The failure this guards against is not a wrong shape but a disappearance - a definition that falls past the fold branch lands at the item's own column 0, where it is skipped as already-extracted and renders as nothing at all.

carve
- - a
 [^f]: x
html
<ul>
  <li>
    <ul>
      <li>a
[^f]: x</li>
    </ul>
  </li>
</ul>

An abbreviation at a list item's content column is still not a definition

2 conformance fixtures

*[TERM]: expansion is recognized only at document level - NORMATIVE, and already pinned inside a block quote and on a list item's MARKER line. The position that was missing is the one where the other definition kinds do the opposite: an item's CONTENT COLUMN, on a continuation line. There the line is item text and defines nothing, so the reference below it renders without an <abbr>.

carve
- a
  *[HTML]: Hyper Text

The HTML spec.
html
<ul>
  <li>a
*[HTML]: Hyper Text</li>
</ul>
<p>The HTML spec.</p>

The contrast is the point: a REFERENCE definition written at that same column IS the item's block, so it renders nothing and resolves. Three definition kinds, one column, two answers - and until now nothing measured the difference at this position.

carve
- a
  [r]: /u

see [t][r]
html
<ul>
  <li>a</li>
</ul>
<p>see <a href="/u">t</a></p>

An abbreviation definition in an item body is paragraph text

5 conformance fixtures

PART 12 §7 says an abbreviation_definition is one only as a direct child of the document: written inside a block quote, a list item or a div, "the line is not a definition at all: it is ordinary paragraph text, it defines nothing, and it is preserved as the text the author typed". So the looseness question §17 L1 asks - does the item hold a blank-line-separated second paragraph - has an answer that follows from §7 rather than from a rule about abbreviations: the line renders, so it IS that paragraph, and the item is loose.

carve
- a

  *[A]: a
html
<ul>
  <li><p>a</p>
    <p>*[A]: a</p>
  </li>
</ul>

Nothing changes when a sublist follows it. The definition-shaped line is already the second paragraph, and §17 L2's attached sub-block cannot take that back:

carve
- a

  *[A]: a
  - b
html
<ul>
  <li><p>a</p>
    <p>*[A]: a</p>
    <ul>
      <li>b</li>
    </ul>
  </li>
</ul>

Looseness is a property of the LIST, so a sibling item is wrapped too:

carve
- a

  *[A]: a
  - b
- c
html
<ul>
  <li><p>a</p>
    <p>*[A]: a</p>
    <ul>
      <li>b</li>
    </ul>
  </li>
  <li><p>c</p></li>
</ul>

The control is the definition kind that IS collected at that column. A link reference definition inside the item renders nothing, resolves for the rest of the document, and leaves the item tight - which is what makes the abbreviation's answer a consequence of §7 rather than an inconsistency:

carve
- a

  [r]: /u

See [x][r].
html
<ul>
  <li>a</li>
</ul>
<p>See <a href="/u">x</a>.</p>

At document level the abbreviation is collected, renders nothing of its own, and expands its term - the behavior the container position does not get:

carve
*[A]: alpha

A here
html
<p><abbr title="alpha">A</abbr> here</p>

A : description line needs a term above it

1 conformance fixture

A definition list is a term plus its descriptions, so a : line with no term above it opens nothing - the line is ordinary paragraph text, and anything on it stays text too.

carve
:  [r]: /u

see [t][r]
html
<p>:  [r]: /u</p>
<p>see [t][r]</p>

A tab as the first character of a definition term

1 conformance fixture

A tab right after the marker's separator space is a different question from the previous one: the separator itself is a literal space, and it is present, so the marker is satisfied and a term forms. The tab is the first character of the term's content, not part of the separator - ordinary leading whitespace there, stripped the same way a bullet's own extra separator spaces never reach the item's text. It is not protected by the tabs-in-code verbatim rule, which covers fenced code content and inline code spans only (carve#698).

carve
:: 	x
html
<dl>
  <dt>x</dt>
</dl>

An abbreviation term is one ASCII alphanumeric word

2 conformance fixtures

abbreviation_term = (letter | digit)+, and letter is enumerated as a..z plus A..Z. So the term is case-blind, may start with a digit, and may be a digit alone - every corpus abbreviation before this one was an uppercase multi-letter word, which is the one shape that hides all of those.

carve
*[dl]: definition list
*[3D]: three dimensional
*[9]: nine

A dl, a 3D one, and 9.
html
<p>A <abbr title="definition list">dl</abbr>, a <abbr title="three dimensional">3D</abbr> one, and <abbr title="nine">9</abbr>.</p>

A term outside that alphabet is not a definition, and the line stays as written rather than being dropped. An abbreviation has no marker at the use site, so a definition swallowed here would take its whole line of prose with it and leave nothing behind to explain the loss.

carve
*[ß]: sharp s
*[e.g.]: for example
*[HTTP API]: an interface

Text about ss and eg below.
html
<p>*[ß]: sharp s
*[e.g.]: for example
*[HTTP API]: an interface</p>
<p>Text about ss and eg below.</p>

A definition inside a definition-list dd is collected, and the entry keeps no trace

2 conformance fixtures

A <dd> continues like a list item (§17, definition_body) and is one of the block-level contexts §17 L6 names: a definition written as its content is collected into the document-wide table and the entry renders empty, exactly as a list item or block quote does. This holds the same way for both definition kinds a <dd> can hold - a link reference definition and a footnote definition - so a fix for one is not a fix for only one (carve#666).

carve
:: term
:  [r]: /u

see [t][r]
html
<dl>
  <dt>term</dt>
  <dd></dd>
</dl>
<p>see <a href="/u">t</a></p>
carve
:: term
:  [^f]: x

see[^f]
html
<dl>
  <dt>term</dt>
  <dd></dd>
</dl>
<p>see<a id="fnref1" href="#fn1" role="doc-noteref"><sup>1</sup></a></p>
<section role="doc-endnotes">
  <hr>
  <ol>
    <li id="fn1">
      <p>x<a href="#fnref1" role="doc-backlink"></a></p>
    </li>
  </ol>
</section>

An empty abbreviation term is not a definition

1 conformance fixture

abbreviation_term = (letter | digit)+ needs at least one character, so *[]: opens nothing and the line stays paragraph text.

carve
*[]: expansion

Text.
html
<p>*[]: expansion</p>
<p>Text.</p>

A definition body continuation indented past its column is lazy text

3 conformance fixtures

definition_indent (resources/grammar.ebnf, PART 2) is a whitespace run REACHING the body's column - the one : establishes. REACHING it is what makes a line the body's own content; going past it does not make the line something else, because there is nothing past that column for indentation to mean. So a line indented further is a continuation of the body's OPEN PARAGRAPH, its content is inline, and a > on it is a greater-than sign rather than a block quote opener.

The alternative reading - extra indentation opens a nested block, the way it does inside a list item - makes indentation depth mean two different things one line apart: the line above continues a paragraph lazily and this one would open a block. carve-js and carve-php read it that way and both move (carve#918).

The two documents after it are CONTROLS. They pin the columns on either side of the boundary, which do not change and are not what was ruled: at the body's own column a block opener still opens a block, and flush left the body ends and the quote is its sibling. Without them the rule above reads as "an indented > is never a quote", which is not what it says.

carve
:: t
:  body
    > q
html
<dl>
  <dt>t</dt>
  <dd>body
&gt; q</dd>
</dl>

CONTROL, at the body's column. Three spaces reach column 3, so the line is the body's own block content and the quote opens.

carve
:: t
:  body
   > q
html
<dl>
  <dt>t</dt>
  <dd>
    <p>body</p>
    <blockquote><p>q</p></blockquote>
  </dd>
</dl>

CONTROL, flush left. Column 0 does not reach the body's column at all, so the body ends and the quote is a sibling of the list.

carve
:: t
:  body
> q
html
<dl>
  <dt>t</dt>
  <dd>body</dd>
</dl>
<blockquote><p>q</p></blockquote>

An abbreviation expands inside an inline container

5 conformance fixtures

PART 9R R3 matches a term in RENDERED TEXT at word boundaries. The container the text sits in does not change that: an ordinary span, a compact semantic span and the :name[…] extension form all expand, exactly as emphasis and a link do.

The corpus had one case here - the explicit-abbr row, which every engine agreed on - so every neighbouring row was unpinned, and two engines kept opposite defects for months with no red test: carve-rs dropped the expansion inside a span, carve-js dropped it inside :name[…] (markup-carve/carve#1151).

carve
*[HTML]: Long Form

The [HTML]{.x} key.
html
<p>The <span class="x"><abbr title="Long Form">HTML</abbr></span> key.</p>

A compact semantic span is the same question, and PART 9 §10 made this spelling a documented feature - so a dropped expansion here is silent loss inside a construct the docs teach.

carve
*[HTML]: Long Form

The [HTML]{kbd} key.
html
<p>The <kbd><abbr title="Long Form">HTML</abbr></kbd> key.</p>

The :name[…] form takes the generic fallback in a core render, and the term still expands inside it.

carve
*[HTML]: Long Form

The :kbd[HTML] key.
html
<p>The <span class="ext-kbd"><abbr title="Long Form">HTML</abbr></span> key.</p>

The controls: emphasis and a link already agreed across engines, and they pin that the containers above are not special-cased in one direction.

carve
*[HTML]: Long Form

Both *HTML* and [HTML](/u) expand.
html
<p>Both <strong><abbr title="Long Form">HTML</abbr></strong> and <a href="/u"><abbr title="Long Form">HTML</abbr></a> expand.</p>

An explicit abbr attribute is the one exception (markup-carve/carve#1127): the authored expansion wins and the definition does not apply on top of it.

carve
*[HTML]: Long Form

The [HTML]{abbr="Custom"} key.
html
<p>The <abbr title="Custom">HTML</abbr> key.</p>

Definition lists

1 conformance fixture

A definition list also does not interrupt a paragraph - a :: line directly under prose folds into that paragraph, so a list needs a blank line before it.

A blank line may separate a term from its definition (or one definition from the next) for readability - a following : line still attaches to the entry:

carve
:: term

:  the definition
html
<dl>
  <dt>term</dt>
  <dd>the definition</dd>
</dl>

A definition (<dd>) ends at a blank line that is followed by neither an indented continuation nor a : definition, at a new :: term, or at a block opener.

Attributes attach to the whole <dl> via a preceding block-attribute line ({.class} on the line before the first :: term). There is deliberately no per-<dt> / per-<dd> attribute form: unlike a list item (-{.c}) or a table row (| … |{.c}), a term or definition takes no glued marker attributes. Style individual terms/definitions with CSS descendant selectors (dl.gloss dt), or put the attributes on the <dl>.

Released under the MIT License.