HTML Lists

Chapter 5 15 mins

Learning outcomes:

  1. What are lists
  2. The <ol> and <ul> elements
  3. Some simple lists
  4. Nesting lists within lists
  5. Things to note regarding <ol> and <ul>

Introduction

So far in this unit, we've learned about a great deal of HTML elements, including <h1> to <h6> for representing headings, <p> for representing paragraphs, <a> for representing hyperlinks, and so on.

Another pretty useful set of elements is that of <ol> and <ul>, used to denote ordered and unordered lists, respectively.

In this chapter, we'll get to unravel what the <ol> and <ul> elements exactly are; their only possible child element, <li>; how to create multiple lists within one another; and much more on this road.

What are lists?

We'll start by defining a list:

A list is simply a collection of items that might be ordered or unordered.

For example, the steps to follow in preparing a meal sit well with an ordered list, since the order of the steps is important.

Similarly, the items in a grocery list can be modeled using an unordered list, since whether 'detergent' comes first or last doesn't matter.

In HTML, there are two fundamental elements to denote lists:

  • <ol> is used to denote ordered lists, hence the name 'ol'.
  • <ul> is used to denote unordered lists, hence the name 'ul'.

Both <ol> and <ul> define each list item using <li>.

The <li> element stands for 'list item' and represents an item of an <ol> or <ul> list. Note that <li> should only be used inside <ol> and <ul>; nothing else.

Conversely, also note that <ol> and <ul> shouldn't directly contain anything besides <li>. (We'll demonstrate what this means below.)

In the next section, we consider a handful of examples of <ol> and <ul>.

Some simple lists

Suppose we want to denote the following collection of programming languages as an unordered list: JavaScript, Ruby, C++, Swift and Perl.

Well, it's really easy to do so.

Since we need an unordered list, we start off with the <ul> element:

<ul></ul>

This denotes our list.

Now inside this <ul> element, we just need to put five <li> elements corresponding to the five programming languages given above.

Something as follows:

<ul>
   <li>JavaScript</li>
   <li>Ruby</li>
   <li>C++</li>
   <li>Swift</li>
   <li>Perl</li>
</ul>

And we're done!

Let's see the output:

  • JavaScript
  • Ruby
  • C++
  • Swift
  • Perl

By default, <ul> lists are rendered with a small filled circle (often referred to as a disk) preceding every list item. This acts as a list item marker.

Also note that lists are slightly spaced out from the left side. This is just so that it's easier for us to distinguish lists from other elements on a webpage.

Once again, as with almost all HTML elements, we can customize all the default styles of <ul> (and <ol>) lists using the power of CSS.

Now, let's consider an example of <ol>.

Suppose we want to list out the following students, in the order given, to represent their positions in a competitive programming tournament: Alice, Bob, Ali.

Once again, this is very straightforward. Take the <ol> element and put each student inside an <li> element. Something as follows:

<ol>
   <li>Alice</li>
   <li>Bob</li>
   <li>Ali</li>
</ol>

And that's done!

Here's the output:

  1. Alice
  2. Bob
  3. Ali

Notice the marker for each list item now, for an ordered list. It's a number corresponding to the position of the <li> element in its parent <ol>.

It's easy enough to remember that <ol> lists are numbered and not <ul> lists: the order matters only in <ol> lists and so, likewise, they are numbered.

While it's possible to change the item markers of <ol> and <ul> lists — even swap them and thus make <ol> lists bulleted and <ul> lists numbered — it's recommended to use numbering only with <ol> and non-numbering only with <ul> lists.

Nesting lists

The hidden power of HTML lists lies in that they can be nested. That is, we can have list items containing lists themselves.

Having such use cases isn't very rare. For example, programming spec documents routinely use nested lists — an algorithm has a list of steps and some of those steps themselves are divided into further substeps.

Let's consider an instance of nesting lists.

We have the following list of languages along with their category:

  • Markup languages: Markdown, HTML, SVG
  • Programming languages: JavaScript, C++, Ruby

Our job is to represent this whole collection of languages as nested lists, with each language listed under its respective category.

First, we'll create an unordered list for the two entries, markup languages and programming languages:

<ul>
   <li>Markup languages</li>
   <li>Programming languages</li>
</ul>

Next, we'll need to put the list of all markup languages inside the first <li> and similarly the list of all programming languages inside the second <li>. Both of these lists will be <ul> themselves as well.

Altogether, we'll get to the following code:

<ul>
   <li>
      Markup languages
      <ul>
         <li>Markdown</li>
         <li>HTML</li>
         <li>SVG</li>
      </ul>
   </li>
   <li>
      Programming languages
      <ul>
         <li>JavaScript</li>
         <li>C++</li>
         <li>Ruby</li>
      </ul>
   </li>
</ul>
  • Markup languages
    • Markdown
    • HTML
    • SVG
  • Programming languages
    • JavaScript
    • C++
    • Ruby

Notice the item markers of the nested <ul> list items here. They aren't filled circles but instead hollow circles.

These different item markers and the added indentation clearly helps us distinguish nested lists from outer-level lists.

Now, while the code above works, there's a slight issue with the category text.

Currently, both 'Markup languages' and 'Programming languages' are written as mere text inside the <li> elements, not marked up by any element. It's much better to put them inside, let's say, a <p>, or possibly an <h2>, etc.

We do this below, using the <p> element:

<ul>
   <li>
<p>Markup languages</p> <ul> <li>Markdown</li> <li>HTML</li> <li>SVG</li> </ul> </li> <li>
<p>Programming languages</p> <ul> <li>JavaScript</li> <li>C++</li> <li>Ruby</li> </ul> </li> </ul>
  • Markup languages

    • Markdown
    • HTML
    • SVG
  • Programming languages

    • JavaScript
    • C++
    • Ruby

The output might not be that much different than what we had before but code-wise this variant is much better than the previous one (with non-marked-up text sitting inside <li>).

The vertical spacing around the category text in the code above is a consequence of the margins applied by default to <p> elements.

Moving on, just for the sake of visualizing nested <ol> lists, let's rewrite the code above, replacing <ul> with <ol>:

<ol>
   <li>
      <p>Markup languages</p>
      <ol>
         <li>Markdown</li>
         <li>HTML</li>
         <li>SVG</li>
      </ol>
   </li>
   <li>
      <p>Programming languages</p>
      <ol>
         <li>JavaScript</li>
         <li>C++</li>
         <li>Ruby</li>
      </ol>
   </li>
</ol>

And now let's see the output:

  1. Markup languages

    1. Markdown
    2. HTML
    3. SVG
  2. Programming languages

    1. JavaScript
    2. C++
    3. Ruby

Alright, so unlike <ul> lists, the item markers in nested <ol> lists remain the same — decimal numbers.

In this discussion, we demonstrated nesting just one list inside another list, but in HTML we can nest as many lists within lists as we want to.

However, the deeper the nesting, the more complex it would become to maintain and work with the list's HTML code. So, it's best to keep the nesting depth of lists to a minimum wherever possible.

Things to note

The <ol>, <ul> and <li> elements are all pretty simple to use. However, there are two things to take special care of when using them.

<ol>/<ul> shouldn't directly contain anything except <li>

First of all, <ol> and <ul> elements can NOT directly contain any element besides <li>.

So, for example, the following is bad HTML:

<ul>
<p>Here are the items:</p> <!-- This is not good! --> <li>Item 1.</li> <li>Item 2.</li> </ul>

The issue here is the <p> element occurring directly inside the <ul> element — we should have nothing directly inside <ol>/<ul> besides the <li> element.

For now, fixing this code is pretty straightforward; just take the <p> outside the <ul>:

<p>Here are the items:</p>
<ul>
   <li>Item 1.</li>
   <li>Item 2.</li>
</ul>

Notice the emphasis on the word 'directly' above; it means that the given rule applies only when we are talking about adding something directly inside <ol> or <ul>.

For example, it's perfectly valid to have a <p> occurring inside a <ul> element, given that it is nested under an <li> element, as follows:

<p>Here are the items:</p>
<ul>
   <li>
<p>This is item 1</p> <!-- Perfectly valid. --> </li> <li>Item 2.</li> </ul>

As a matter of fact, we can have any element inside <li> (that is also valid to be used inside the <body> element).

<li> shouldn't go anywhere except for in <ol>/<ul>

Conversely, it's also NOT considered good practice to have the <li> element appearing inside any other element besides <ol> or <ul>.

Likewise, the following code is again bad HTML:

<p>Here are the items:</p>
<p> <li>Item 1.</li> <!-- <li> shouldn't go inside <p>! --> <li>Item 2.</li> <!-- same here -->
</p>

Whenever you use <li>, make sure that it's inside <ol> or <ul>.

"I created Codeguage to save you from falling into the same learning conundrums that I fell into."

— Bilal Adnan, Founder of Codeguage