Skip to content

MD077 - List continuation content indentation

Aliases: list-continuation-indent

What this rule does

Checks that continuation content inside a list item lines up with the item's content column (the W+N rule from the CommonMark spec). Two mistakes are flagged:

  • Under-indentation after a blank line, which lets the content escape the list item and render as a separate paragraph.
  • Over-indentation, in both tight continuation (no blank line) and loose continuation (after a blank line), which pushes the body past the content column so it no longer aligns under the item text.

Content indented to the content column + 4 or more after a blank line is an indented code block, not continuation, and is left untouched. Under the MkDocs flavor, a minimum of 4 spaces is enforced to satisfy Python-Markdown's stricter requirement.

Why this matters

  • Rendering correctness: Insufficient indentation after a blank line causes the content to "escape" the list item. Most renderers will close the list and render the content as a separate paragraph, which is usually not what the author intended.
  • MkDocs compatibility: Python-Markdown (used by MkDocs) requires at least 4 spaces of indentation for ordered list continuation, even when the marker is only 3 characters wide (e.g., 1.). CommonMark accepts 3 spaces in this case, so documents can silently break when deployed to MkDocs.

Examples

Unordered list

Correct

- Item

  Continuation paragraph (2-space indent matches `- ` marker width).

Incorrect

- Item

 Continuation paragraph (1-space indent — not enough for `- ` marker).

Note: Content at 0 indent after a blank line starts a new paragraph and is not flagged. MD077 only flags content with partial indentation (above the marker column but below the content column), which signals an indentation mistake rather than an intentional new paragraph.

Ordered list (CommonMark)

Correct

1. Item

   Continuation paragraph (3-space indent matches `1. ` marker width).

Incorrect

1. Item

  Continuation paragraph (2-space indent — not enough for `1. ` marker).

Ordered list (MkDocs flavor)

Correct

1. Item

    Continuation paragraph (4-space indent required by Python-Markdown).

Incorrect

1. Item

   Continuation paragraph (3 spaces — valid CommonMark but breaks in MkDocs).

Multi-digit markers

10. Item

    Continuation paragraph (4-space indent matches `10. ` marker width).

Flavor-aware behavior

Flavor Required indent
Standard content column (W+N from marker width)
MkDocs max(content column, 4)

Under MkDocs flavor, both ordered and unordered list items require at least 4 spaces of continuation indent to ensure Python-Markdown compatibility.

Code blocks inside list items

An under-indented fenced code block (``` or ~~~) is checked and fixed, because too little indentation lets the block escape the list item. The content between the fences is not inspected for its own indentation; only the opener and closer lines decide whether the block belongs to the list item.

1. Item

    ```toml        ← checked (fence opener)
    key = "value"  ← not checked (code content)
    ```             ← checked (fence closer)

Note: The automatic fix for an under-indented block reindents the fence opener and closer up to the list item's content column. Interior lines that sit below the content column are promoted up to it (so the fence stays paired inside the list item's scope); interior lines already at or above the content column keep their indent. You may still want to manually adjust interior alignment for visual consistency.

Over-indented code blocks are left untouched. An over-indented fenced block still renders correctly inside the list item, and moving only its delimiters (the body is not reindented) would change the literal code content. So unlike prose, an over-indented code block is not flagged or fixed.

Tight continuation (no blank line)

Content that directly follows a list item without a blank line is called "tight continuation." MD077 flags tight continuation lines that are over-indented — indented beyond the item's content column:

1. Item
    Over-indented continuation (4 spaces — should be 3 for `1. `).

The same normalization applies after a blank line (loose continuation). A body line indented past the content column, but not far enough to become an indented code block (content column + 4), is snapped back to the content column:

* Item

   Over-indented after a blank line (3 spaces, snapped back to 2 for `* `).

Zero-indent lazy continuation is valid CommonMark and is not flagged:

- Item
continuation (lazy — not flagged by MD077)

Correctly indented tight continuation is also not flagged:

1. Item
   Correctly indented continuation (3 spaces matches `1. ` width).

GFM task list items

Task list items (- [ ], - [x], - [X], and the same with *, +, or ordered markers) accept two valid continuation columns:

  1. The item's CommonMark content column (same as for any other list item).
  2. The column after the checkbox prefix — content_column + 4 for [ ], [x], or [X].

Both layouts are treated as correct so MD077 does not fight with MD013's reflow-mode = "normalize", which wraps long task items at the post-checkbox column to keep the text visually aligned under the task body. Without this accommodation MD077 would re-flag every reflowed task line and the fix loop would never converge.

- [ ] Long task text
  continuation at column 2 (content column) — valid.

- [ ] Long task text
      continuation at column 6 (post-checkbox) — valid.

- [ ] Long task text
    continuation at column 4 — flagged (neither column).

When a continuation is flagged, the auto-fix snaps to the nearer of the two valid columns. For example, wrap (7 spaces) under - [ ] is 1 away from column 6 and 5 away from column 2, so it's repaired to 6 — preserving the author's apparent intent to align after the checkbox.

Equidistant ties: context-aware resolution

When the flagged indent is exactly equidistant from both valid columns (for example, 4 spaces under - [ ], which is 2 away from both column 2 and column 6), the fix looks at other continuation lines in the same item to infer which column the author is already using. The tie resolves to that column:

Siblings at content col Siblings at task col Tie resolves to
no no content col
yes no content col
no yes task col
yes yes content col

When siblings exist at both valid columns the author's pattern is self-contradictory, so the fix falls back to the CommonMark-canonical content column. When no siblings give a signal, the fix also falls back to the content column.

Automatic fixes

This rule can automatically fix violations by adjusting the leading whitespace to the required indent level.

rumdl check --fix document.md