Nested Lists
A nested list lets one item carry a second layer of detail: a feature and its sub-features, a step and the sub-steps inside it, a category and the entries under it. Markdown has no syntax for nesting at all. There is no nested keyword, no closing tag, no wrapper element. The hierarchy exists in exactly one place — the whitespace at the start of the line — and that makes the indentation rules the only thing you really have to learn on this page.
The rule is narrower than the folklore suggests and wider than the four spaces that many tutorials insist on. What decides whether a line is a child is not the number of spaces you type but the column where the parent item’s text starts, and that column is the width of the parent’s marker. Two spaces and four spaces both work, three spaces work too, and so does any value inside a range whose upper end is a hard boundary: four spaces past the content column and the parser stops reading a list and starts reading a code block.
A child list is a list that is indented into the item above it:
- Level one
- Level two
- Level three
- Another item
<ul>
<li>Level one
<ul>
<li>Level two
<ul>
<li>Level three</li>
</ul>
</li>
</ul>
</li>
<li>Another item</li>
</ul>
The child list sits inside the <li> of its parent, and the last item returns to the top level because its indentation matches the first one. Nothing in the source marks the end of a child list; the indentation alone decides where each level begins and ends.
The indentation a child needs is measured from the width of the parent’s marker, not from a fixed number:
| Parent marker | Marker width | Child indent |
|---|---|---|
- plus a space | 2 columns | 2 columns |
1. plus a space | 3 columns | 3 columns |
10. plus a space | 4 columns | 4 columns |
So the advice that a second level always needs four spaces is a habit, not a rule. Four spaces work under a dash, and they also work under 1. — you are then one column to the right of the content column, which is still inside the range that counts as a child list. What does not work is going too far. Four spaces past the content column turns the continuation into an indented code block:
- Level one
this is code, not a list
The item text is followed by a <pre><code> block instead of a second paragraph, so the six spaces turned the content into code. Note the blank line. Indented code cannot interrupt a paragraph, so the code block only forms when the line is separated from the item text; without that blank line the same six spaces simply continue the paragraph.
Indenting too little is the more common mistake, and its result is easy to miss. A line that is not indented far enough does not become a child of the item above it; it breaks out and becomes a separate list:
1. Parent
- Child
<ol>
<li>Parent</li>
</ol>
<ul>
<li>Child</li>
</ul>
Two spaces were not enough under a 1. marker, whose text starts in the fourth column, so the bullet list escaped and became a sibling of the ordered one. Indent to three spaces and the bullet becomes a genuine child. The same rule explains the case where a child turns out to be a sibling: it was indented less than the content column of its parent, so the parser read it as a new block at the outer level.
Levels may change type freely. A bullet list may contain an ordered list, and an ordered list may contain a bullet list. The indentation rule does not change, because it is still measured from the parent marker:
- Prepare the release
1. Tag the commit
2. Publish the notes
- Announce the release
The result is one <ul> whose first item contains a nested <ol>, and the second item is a plain sibling of the first. The mixed form is the natural way to say “these are the phases” while listing “these are the steps” underneath one of them. It also has a cost: every change of level changes the width of the marker, so the indentation has to change with it, and a file that mixes the two is easy to break with a stray space.
Three levels is usually as deep as a list should go. A fourth level is possible, but the cost is real: the text of the deepest item starts nine columns in, the line wraps earlier, and the reader has to count the indents to work out which parent an item belongs to. Past three levels a list stops being a scannable structure and becomes a paragraph with punctuation, and the better move is to break the structure apart. A list of features with three sub-points each becomes a section per feature, with the sub-points as a short list inside it. You keep the same information, you give each level its own heading, and the heading carries the hierarchy that the whitespace was carrying before. A nested list is best when the second level is short; when the second level needs paragraphs of its own, it wants to be a section.
| Child indent | Actually renders as | Why |
|---|---|---|
2 spaces under - | a nested list | the content column is the third column |
6 spaces under - | an indented code block | four spaces past the content column |
2 spaces under 1. | a separate sibling list | the content column is the fourth column |
| siblings indented 2 and 4 | one child list, but only by luck | both values are still inside the child range |
Do not mix tabs and spaces when you indent. The specification allows a tab to stand for four spaces, but editors disagree about how wide a tab is: the same indent is four columns in one editor and eight in another, and the second one may push your list over the code-block threshold. A file that indents with tabs on one line and spaces on the next is even worse, because the two are not comparable at all. Pick spaces, use the same count everywhere, and let the editor’s “convert indentation on save” setting normalize whatever you paste in.
Rewrite the following plain text as Markdown. Use one unordered list for the two top-level items, put two children under the first item, put an ordered list of two steps under the second item, and indent every level to the column where the parent item’s text starts. Use spaces throughout, never tabs.
Set up the project
Install pnpm
Run pnpm install
Configure the build
1. Set the target
2. Build the output
Approach:
The two top-level items are siblings, so they share one unordered list and one indent level. The children under the first item are two spaces in, because a dash marker occupies two columns. The ordered list under the second item is a child of that item, so it is indented to the same two-space column, and its own items are numbered with a period and a space.
Steps:
- Write the two top-level items as a hyphen, a space, and the text, all at the left margin.
- Indent the two children of the first item by two spaces and give each of them a hyphen and a space, so that they line up with the column where the parent’s text starts.
- Indent the ordered list under the second item by two spaces as well, and write its two items as
1.and2.followed by a space. - Check the result: rendering it must produce a two-item bullet list whose first item holds a nested bullet list and whose second item holds a nested ordered list numbered 1 and 2.
Answer:
- Set up the project
- Install `pnpm`
- Run `pnpm install`
- Configure the build
1. Set the target
2. Build the outputYou can now create a nested list of any depth with indentation alone, and you know that the amount of indentation is measured from the width of the parent’s marker rather than from a fixed number of spaces. You know that two, three and four spaces can all be correct depending on the parent, that indenting too little turns a child into a sibling or a separate list, and that four spaces past the content column turns the content into a code block. You also know that ordered and unordered levels may be mixed freely, and that a list deeper than three levels is usually a sign that the content should become a section. The next page turns to the blockquote, the other block element in this chapter, where the rule that matters is not the marker but the range.
