HTML Lists & Structured Content Nested Lists in HTML

We’ve come a long way in this HTML series. In the previous two articles, we broke down unordered lists with bullet points and figured out ordered lists with numbering and sequencing. Those are genuinely useful on their own.

But here’s where it gets interesting: real-world content is rarely flat. Think about a cooking tutorial where step 3 has three sub-steps of its own. Or a course outline with modules that contain individual lessons. Or a legal document with clauses and sub-clauses. A single level of list doesn’t capture that structure, and dumping everything flat into one list loses the relationships between items.

That’s what nested lists HTML is about: building hierarchy that reflects how information actually works.

And honestly, once you see how it fits together, you’ll start spotting it everywhere.


01The One Rule That Governs All Nesting

Before anything else, there’s one rule you absolutely need to know. It’s the rule that trips up almost every beginner the first time they try nesting, and it’s simple once you hear it:

A nested list always goes inside an <li> element, not directly inside <ul> or <ol>.

That’s it. That’s the rule. Let’s look at why it matters.

The Golden Rule: Where the Nested List Lives
✗ Incorrect
<ul>
<li>Shopping</li>
<ul> <!– ❌ Direct child of ul –>
<li>Milk</li>
</ul>
</ul>
✓ Correct
<ul>
<li>Shopping
<ul> <!– ✅ Inside <li> –>
<li>Milk</li>
</ul>
</li>
</ul>

The reason is straightforward: <ul> and <ol> are only allowed to have <li> elements as their direct children. If you put another list directly inside a <ul>, you’re breaking HTML’s rules. The browser will usually try to render it anyway, but your structure is technically invalid, screen readers may behave unpredictably, and validators will flag it as an error.

Put the inner list inside the <li>, and everything works the way it’s supposed to.


02Your First Nested List in HTML

Let’s start with the most common case: an unordered list inside another unordered list. You’ll need this for things like navigation menus, category breakdowns, and grouped content.

<ul>
  <li>Fruits
    <ul>
      <li>Mango</li>
      <li>Strawberry</li>
      <li>Blueberry</li>
    </ul>
  </li>
  <li>Vegetables
    <ul>
      <li>Spinach</li>
      <li>Broccoli</li>
    </ul>
  </li>
  <li>Grains
    <ul>
      <li>Brown Rice</li>
      <li>Oats</li>
    </ul>
  </li>
</ul>

Notice how each parent <li> (Fruits, Vegetables, Grains) has a nested <ul> sitting inside it, after the text. The browser will automatically indent the inner list visually, which is helpful for understanding the hierarchy at a glance.

One thing to pay attention to: the parent <li> tags that wrap an inner list still need their closing </li> tag after the inner </ul>. Forgetting that closing tag is probably the most common mistake people make with nested lists HTML.


03HTML Nested Ordered Lists: When the Order Matters at Every Level

Sometimes your content has a numbered hierarchy. Legal documents, academic outlines, technical specifications, and step-by-step tutorials often work this way. When you need numbering at every level, you’re working with html nested ordered lists.

<ol>
  <li>Set Up Your Project
    <ol>
      <li>Create a project folder</li>
      <li>Open the folder in your code editor</li>
      <li>Create an index.html file</li>
    </ol>
  </li>
  <li>Write Your HTML
    <ol>
      <li>Add the DOCTYPE declaration</li>
      <li>Add the html, head, and body tags</li>
      <li>Write your content inside body</li>
    </ol>
  </li>
  <li>Open in a Browser
    <ol>
      <li>Find the file in your file explorer</li>
      <li>Double-click to open in your default browser</li>
    </ol>
  </li>
</ol>

Something worth noting: each inner <ol> starts counting from 1 again. That’s expected behavior. The browser treats each nested list as a fresh sequence. So you’ll see 1, 2, 3 at the top level, and 1, 2, 3 again inside each of those items.

If you want the sub-items to use a different numbering style, like lowercase letters or Roman numerals, the type attribute (which we covered in the ordered lists article) works perfectly here. You can set type="a" on the inner <ol> to get a, b, c instead of 1, 2, 3, which is great for formal outlines.

<ol>
  <li>Chapter One: Getting Started
    <ol type="a">
      <li>Introduction to the Topic</li>
      <li>Key Terms and Definitions</li>
      <li>Why This Matters</li>
    </ol>
  </li>
  <li>Chapter Two: Core Concepts
    <ol type="a">
      <li>The Fundamentals</li>
      <li>Common Patterns</li>
    </ol>
  </li>
</ol>

This gives you the classic “1. a. b. c.” outline format that academic and professional documents use all the time. Clean and structured.


04Mixing List Types: The Real Power of Multi-Level Lists

Here’s something that a lot of tutorials skip over: you don’t have to use the same list type at every level. You can nest a <ul> inside an <ol>, or an <ol> inside a <ul>. HTML doesn’t care. The meaning you assign to each level is what matters.

This is where multi level lists really start to shine for content structure. Think about a recipe: the top level is ordered (because steps have a sequence), but each step might have a sub-list of ingredients that don’t need any particular order among themselves.

<ol>
  <li>Prepare your ingredients
    <ul>
      <li>2 cups of flour</li>
      <li>1 teaspoon of salt</li>
      <li>1 cup of warm water</li>
      <li>1 tablespoon of olive oil</li>
    </ul>
  </li>
  <li>Mix the dry ingredients together</li>
  <li>Add the wet ingredients gradually
    <ul>
      <li>Add water little by little</li>
      <li>Stir continuously as you pour</li>
    </ul>
  </li>
  <li>Knead until smooth, then let it rest</li>
</ol>

The outer <ol> tells both browsers and screen readers that these steps happen in order. The inner <ul> tells them the sub-items are a group without a specific sequence. The combination communicates more than either list type would alone.

You can go the other way too, a <ul> on the outside with an <ol> nested inside when you have categories that don’t need ranking, but each category contains steps that do:

<ul>
  <li>Morning Routine
    <ol>
      <li>Wake up at 6:30 AM</li>
      <li>Drink a glass of water</li>
      <li>Exercise for 20 minutes</li>
      <li>Shower and get ready</li>
    </ol>
  </li>
  <li>Work Block
    <ol>
      <li>Review today's tasks</li>
      <li>Work on the highest priority item first</li>
      <li>Take a short break after 90 minutes</li>
    </ol>
  </li>
</ul>

05Going Three Levels Deep

You can nest as deep as the HTML specification technically allows, but three levels is the sweet spot for almost every use case. Four or five levels deep usually means your content structure needs rethinking, not more nesting.

That said, three levels are genuinely useful. Course outlines, technical documentation, and detailed tutorials often need them.

<ol>
  <li>Frontend Development
    <ol type="a">
      <li>HTML
        <ul>
          <li>Document structure</li>
          <li>Semantic elements</li>
          <li>Forms and inputs</li>
        </ul>
      </li>
      <li>CSS
        <ul>
          <li>Box model</li>
          <li>Flexbox and Grid</li>
          <li>Responsive design</li>
        </ul>
      </li>
    </ol>
  </li>
  <li>Backend Development
    <ol type="a">
      <li>Server Basics
        <ul>
          <li>HTTP and requests</li>
          <li>APIs and responses</li>
        </ul>
      </li>
    </ol>
  </li>
</ol>
Three-Level Nesting: How It Looks as a Tree
Frontend Development<ol> — Level 1
HTML<ol type=”a”> — Level 2
Document structure<ul> — Level 3
Semantic elements<ul> — Level 3
CSS<ol type=”a”> — Level 2
Box model<ul> — Level 3
Backend Development<ol> — Level 1
Level 1 (outer ol)
Level 2 (inner ol type=”a”)
Level 3 (innermost ul)

Each level serves a different purpose: the first level groups by domain, the second by technology, the third by individual topic. That clarity is exactly what multi level lists are designed for.


06Styling Multi-Level Lists with CSS

By default, browsers already apply some indentation and change the bullet style between levels (disc at level 1, circle at level 2, square at level 3 for unordered lists). But you’ll often want to control this yourself.

A heads-up before this section: we’re touching on CSS here because it’s directly relevant to how nested lists HTML looks and behaves visually. CSS will be covered in full detail later in the series, so don’t worry if some of the syntax looks new.

Here’s a pattern for targeting different nesting levels:

/* Level 1: top-level items */
ul {
  list-style-type: disc;
  padding-left: 1.5rem;
}

/* Level 2: first nested list */
ul ul {
  list-style-type: circle;
  padding-left: 1.25rem;
}

/* Level 3: second nested list */
ul ul ul {
  list-style-type: square;
  padding-left: 1.25rem;
}

/* Same pattern works for ordered lists */
ol {
  list-style-type: decimal;
}

ol ol {
  list-style-type: lower-alpha;
}

ol ol ol {
  list-style-type: lower-roman;
}

The CSS selector ul ul means “a ul that is inside another ul“. It doesn’t matter how many elements are between them, it targets any descendant ul within a ul. That’s exactly what you need for multi-level styling.

How List Markers Look at Each Level

Unordered Levels

  • Level 1 item
  • Level 2 item
  • Level 3 item

Ordered Levels

  • 1.Level 1 item
  • a.Level 2 item
  • i.Level 3 item

Mixed Types

  • 1.Ordered parent
  • Unordered child
  • a.Ordered grandchild

One CSS thing that catches people off guard: browsers apply default padding to lists, and that padding stacks up with nesting. If your multi level lists look too indented on mobile, you may need to reduce the padding-left on nested lists. Start with around 1rem and adjust from there.


07How to Outline Complex Information with Nested Lists HTML

One of the best uses of nested lists is building proper content outlines. You see this in table of contents sections, documentation hierarchies, and course curricula. The structure of your HTML list actually reflects the intellectual structure of your content.

Here’s a real example of a course curriculum outline built with html nested ordered lists:

<ol>
  <li>Introduction to Web Development
    <ol type="a">
      <li>What is the web and how does it work?</li>
      <li>Setting up your development environment</li>
      <li>Your first HTML page</li>
    </ol>
  </li>

  <li>HTML Foundations
    <ol type="a">
      <li>Document structure and the DOCTYPE
        <ul>
          <li>The html, head, and body tags</li>
          <li>Meta tags and their purpose</li>
        </ul>
      </li>
      <li>Text content elements
        <ul>
          <li>Headings, paragraphs, and line breaks</li>
          <li>Bold, italic, and semantic formatting</li>
        </ul>
      </li>
      <li>Lists: unordered, ordered, and nested</li>
    </ol>
  </li>

  <li>Adding Links and Navigation
    <ol type="a">
      <li>Anchor tags and href values</li>
      <li>Internal vs external links</li>
      <li>Building a simple navigation menu</li>
    </ol>
  </li>
</ol>

This structure is semantically rich. It tells search engines, screen readers, and anyone reading your source code exactly how the content is organized. That’s not something you can replicate with visual spacing or divs alone.

💡

Good to know: When you read the HTML source of well-built documentation sites, wikis, and educational platforms, you’ll almost always find nested lists behind the structured navigation and outlines. The HTML structure and the visual hierarchy match because that’s what HTML is for: representing meaning, not just appearance.


08Nested Lists HTML and Accessibility: What Screen Readers Actually Say

This part matters a lot, and it’s one that developers often don’t think about until they try using a screen reader themselves.

Screen readers like NVDA, JAWS, and VoiceOver don’t just read list items one by one. They announce the list structure too. When a user navigates into a list, the screen reader says something like “list, 3 items” or “list of 3 items”. When they enter a nested list, it announces the new level and its item count. When they leave it, it announces that they’ve exited the sub-list and returned to the parent.

What a Screen Reader Announces for a Nested List
🔊
“list, 3 items” — entering the outer <ul>
🔊
“Fruits” — reading the first <li> text
🔊
“list, 3 items” — entering the nested <ul> inside that <li>
🔊
“Mango, 1 of 3” — first item in the inner list
🔊
“Strawberry, 2 of 3”
🔊
“end of list” — exiting the inner list, back to outer
🔊
“Vegetables” — continuing with next outer <li>

This is why correct HTML nesting matters so much for accessibility. When you put a nested list directly inside a <ul> instead of inside a <li>, the screen reader gets confused. The item count is wrong. The nesting context is broken. Users who rely on screen readers are navigating in the dark.

Writing semantically correct nested lists HTML isn’t just about validation. It’s about building something that works for everyone who uses it.

A few accessibility notes specific to nesting:

Don’t nest just for visual indentation. If you need visual indentation, use CSS margins. Nesting a list creates a semantic parent-child relationship, and screen readers will announce that structure. If the relationship doesn’t exist in your content, don’t create it in your HTML.

Keep nesting depth reasonable. Going four or five levels deep makes navigation genuinely difficult for screen reader users. If your structure needs that many levels, consider whether a different HTML structure (like a definition list, a table, or headings with sections) might serve your users better.

Don’t skip levels either. Going from a top-level list directly to a third-level nested list without a second level in between produces confusing screen reader output. If you’re referencing our earlier piece on heading hierarchy, the thinking is similar: skipping levels creates gaps in the structure that assistive technology can’t bridge cleanly.


09When to Use Nesting vs When to Use Separate Lists

Not every situation that looks like it needs nesting actually does. Here’s how to think about it.

Use nesting when items have a genuine parent-child relationship. A chapter and its sections. A category and its members. A step and its sub-steps. The inner items belong to and are defined by their parent item.

Use separate lists when items are parallel and independent. A list of features, followed by a list of limitations. Two different grocery categories on separate parts of the page. There’s no hierarchy between them, so don’t force one.

A common mistake: using nested lists to create visual indentation when you actually need CSS. We discussed this in the unordered lists article, where we looked at how browsers apply default margins and padding. If you just want something to look indented, add padding-left with CSS. Don’t invent a structural relationship that doesn’t exist in your content.

Another situation: if you find yourself with a single-item nested list (a parent with only one child), that’s usually a sign that the child should either be part of the parent text or not nested at all.


10Common Mistakes That Break Multi-Level Lists

Let’s go through the errors you’ll most likely run into:

Forgetting the closing </li> tag after a nested list. This is the most common one. When an <li> contains a nested list, the closing tag goes after the inner list’s closing tag, not before it. People often close the <li> before the nested <ul> starts, which is wrong.

<!-- Wrong: </li> before the nested list -->
<ul>
  <li>Fruits</li>   <!-- ❌ Closed too early -->
    <ul>
      <li>Mango</li>
    </ul>
</ul>

<!-- Correct: </li> after the nested list -->
<ul>
  <li>Fruits         <!-- ✅ Left open -->
    <ul>
      <li>Mango</li>
    </ul>
  </li>              <!-- ✅ Closed here, after inner </ul> -->
</ul>

Putting the nested list outside the <li>. We covered this with the golden rule earlier. It’s worth repeating because it’s the error that causes the most invisible bugs: technically the browser renders something, but the structure is wrong, screen readers miscount items, and validators complain.

Using nesting for visual indentation only. If there’s no semantic reason for the hierarchy, use CSS instead.

Going too deep. Three levels is usually the maximum that makes sense for real content. If you’re at level four or five, sit back and ask whether the structure needs rethinking. Maybe some of those levels should be separate sections with headings instead.

Inconsistent indentation in your source code. HTML doesn’t care about indentation, but humans reading your code do. Nested lists can get tangled fast. Good indentation in your source makes it much easier to spot mismatched tags.


11A Complete Real-World Page Example

Let’s put it all together. Here’s a full page example showing a structured sidebar table of contents, which is one of the most practical uses of nested lists HTML in real websites:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Web Development Guide</title>
  <style>
    body {
      font-family: system-ui, sans-serif;
      max-width: 700px;
      margin: 2rem auto;
      padding: 0 1rem;
      line-height: 1.6;
    }

    nav ol {
      list-style-type: decimal;
    }

    nav ol ol {
      list-style-type: lower-alpha;
      padding-left: 1.5rem;
    }

    nav ol ol ul {
      list-style-type: disc;
      padding-left: 1.25rem;
    }

    nav li {
      margin-bottom: 0.4rem;
    }

    nav a {
      color: #4f46e5;
      text-decoration: none;
    }

    nav a:hover {
      text-decoration: underline;
    }
  </style>
</head>
<body>

  <h1>Web Development Guide</h1>

  <nav aria-label="Table of Contents">
    <h2>Table of Contents</h2>
    <ol>
      <li><a href="#html">HTML Fundamentals</a>
        <ol type="a">
          <li><a href="#html-structure">Document Structure</a>
            <ul>
              <li><a href="#doctype">DOCTYPE and root element</a></li>
              <li><a href="#head">The head section</a></li>
            </ul>
          </li>
          <li><a href="#html-text">Text and Typography</a></li>
          <li><a href="#html-lists">Lists and Structure</a></li>
        </ol>
      </li>

      <li><a href="#css">CSS Styling</a>
        <ol type="a">
          <li><a href="#selectors">Selectors and Specificity</a></li>
          <li><a href="#layout">Layout Techniques</a>
            <ul>
              <li><a href="#flexbox">Flexbox</a></li>
              <li><a href="#grid">CSS Grid</a></li>
            </ul>
          </li>
        </ol>
      </li>

      <li><a href="#js">JavaScript Basics</a>
        <ol type="a">
          <li><a href="#variables">Variables and Data Types</a></li>
          <li><a href="#functions">Functions and Scope</a></li>
          <li><a href="#dom">The DOM</a></li>
        </ol>
      </li>
    </ol>
  </nav>

</body>
</html>

Notice a few things in that example: the entire list is wrapped in a <nav> element with an aria-label, which we covered in the navigation menus article. The list items contain anchor links. The three levels use decimal, lower-alpha, and disc styling respectively. It’s clean, semantic, accessible, and does exactly what a table of contents needs to do.


12Quick Reference: Nested Lists HTML Cheat Sheet

What You Want How to Do It
Nested unordered list Put <ul> inside a <li>, not directly in the parent <ul>
HTML nested ordered lists Put <ol> inside a <li>, use type attribute to vary numbering per level
Mix list types Freely combine <ul> and <ol> at different levels, just keep them inside <li>
Style different levels Use CSS selectors like ul ul, ol ol, ul ul ul to target depth
Change bullet style per level Set list-style-type using CSS: disc circle square for ul, decimal lower-alpha lower-roman for ol
Recommended max depth 3 levels for most content, 4 only when truly necessary
Accessibility rule Only nest when a real parent-child relationship exists in the content
Most common mistake Placing the inner list outside its parent <li>, or not closing the parent <li> after the inner list

13What You Learned Today

Nested lists HTML is one of those topics that sounds straightforward until you start trying to structure real content. The rule is simple: inner lists go inside <li> elements. But how you apply that rule, when you mix list types, how deep you go, and how you style each level, is where good HTML judgment comes from.

Here’s what this article covered:

The core rule: a nested list always lives inside a <li>, not directly inside its parent list. Nesting <ul> inside <ul> for grouped content, and building html nested ordered lists with <ol> inside <ol> for formal outlines. Mixing list types to communicate different kinds of relationships at different levels. Using CSS descendant selectors to style multi level lists visually without touching the HTML structure. Writing accessible nested structure that screen readers can navigate clearly. And knowing when to nest versus when separate lists or different HTML entirely is the better choice.

Next up in this series, we’re moving into tables: a completely different structure for displaying data that belongs in rows and columns. Once you’ve got lists and tables both in your toolkit, you can organize almost any kind of content in HTML.

You’re building solid fundamentals. Keep going.

Nested Lists in HTML

Choose a difficulty to load your challenge

Loading challenge…

Ready to Practice?

Select a difficulty level above to load your challenge.

Easy

1
Live Preview
Great Work!