Skip to content

Step 1 of 5 · Reading · ~3 min

Read

Lists & Code

Tight vs Loose Lists

Two lists that differ by a single blank line produce different HTML. This is not a rendering quirk you can ignore — it is in the spec, every conforming parser does it, and it is the rule most weekend Markdown parsers get wrong.

The same items, two shapes

Tight — no blank line anywhere between the items:

<ul>
<li>alpha</li>
<li>beta</li>
</ul>

Loose — one blank line somewhere between two items:

<ul>
<li>
<p>alpha</p>
</li>
<li>
<p>beta</p>
</li>
</ul>

Note what changed: every item gained a <p> wrapper, not just the ones adjacent to the blank line. Looseness is a property of the whole list. That is what makes it awkward to implement — you cannot decide how to render item one until you have read item five.

What exactly makes a list loose?

Two conditions, either one is enough:

  1. Any two of its items are separated by a blank line.
  2. Any single item directly contains two block-level elements with a blank line between them.

And what does not count is just as important:

SituationVerdict
✓ blank line between item one and item twoloose
✓ an item holding two paragraphsloose
✗ blank line before the first itemtight
✗ blank line after the last itemtight — that blank just ends the list
✗ blank line inside a fenced code block in an itemtight
✗ blank line inside a sublistouter tight, sublist loose

That last row catches people. Nesting means a document can hold a tight list whose child list is loose, side by side.

Rendering diagram…

Detecting it in one pass

Carry a "did I just see a blank line?" flag and only promote to loose when the next item actually arrives:

python

Line three is the whole trick. The trailing blank sets gap, but no item ever follows it, so loose is never set. Collect first, decide second, render third.

Why the spec bothers

Tight lists render compactly because the item text is not a paragraph and gets no paragraph margin. Loose lists give every item full paragraph spacing, which is what you want when items are several sentences long or contain sub-blocks. The author signals the choice with whitespace; the parser has to honour it.

Your exercise

Render one unordered list as tight or loose.

The mistake the grader catches is applying looseness only to the items after the blank line. A hidden test feeds four items with the gap between the second and the third and expects all four wrapped in <p>. If you set a flag mid-loop and start wrapping from that point on, items one and two come out bare and the diff shows exactly two wrong lines out of twelve.

The other one is the trailing blank line: a test ends the input with a blank after the last item and still expects the tight rendering. Only promote to loose when a blank line is followed by another item.

Up nextNested ContainersLists & Code

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…