HTML Unordered Lists
An unordered list groups related items together and displays each one with a bullet marker instead of a number. It’s the element you reach for whenever the order of the items doesn’t matter — a shopping list, a set of features, a group of navigation links — and it’s one of the most common structural building blocks on the web, quietly forming the backbone of menus, sidebars, and content lists on nearly every page you visit.
Overview: How Unordered Lists Work
An unordered list is built from two elements working together: <ul> (the list container) and <li> (each list item). The <ul> element itself does not display any text — it simply tells the browser, and any assistive technology reading the page, "everything inside me is a set of list items." Each individual <li> child is what actually holds the content of one entry.
This is a case where semantics and presentation are deliberately separated. <ul> communicates meaning — a collection of related, order-independent items — while the bullet symbol you see on screen is purely a default visual convention supplied by the browser’s built-in stylesheet. That visual style (the bullet shape, the indentation) can be changed with CSS without changing the meaning of the markup at all. This course focuses on the markup; visual styling of list markers is covered in the CSS course.
By default, browsers render each <li> as a block-level box with display: list-item, add left indentation (typically via padding on the <ul>), and generate a bullet (a filled circle, or "disc") before each item’s content. In the DOM tree, the <ul> becomes a parent node with one or more <li> element nodes as children, and each <li> can itself contain text, inline elements like <a> or <strong>, or even block-level content such as another entire list.
Syntax
<ul>
<li>First item</li>
<li>Second item</li>
<li>Third item</li>
</ul>
The parts of this structure:
<ul>...</ul>— the container for the whole list. Only<li>elements (and a couple of rarely-used script-support elements) are valid direct children.<li>...</li>— one list item. It can hold plain text, links, images described elsewhere, or a nested list.- Global attributes —
<ul>and<li>accept the standard global attributes such asidandclass, which are useful hooks for CSS or JavaScript.
Older HTML allowed a type attribute on <ul> (for example type="square") to control the bullet shape, and a compact attribute to tighten spacing. Both are obsolete in modern HTML — use the CSS list-style-type property instead, which gives you the same control (and more) without mixing presentation into your markup.
Examples
Example 1: A basic list
<ul>
<li>Milk</li>
<li>Eggs</li>
<li>Bread</li>
</ul>
Result: The browser displays three lines, each indented and preceded by a solid bullet (•): "Milk", "Eggs", and "Bread", stacked vertically.
This is the simplest possible unordered list. Each grocery item is its own <li>, and the browser handles indentation, spacing between items, and the bullet marker automatically — no CSS required to get a readable, accessible list.
Example 2: A nested (multi-level) list
<ul>
<li>Fruits
<ul>
<li>Apple</li>
<li>Banana</li>
</ul>
</li>
<li>Vegetables
<ul>
<li>Carrot</li>
<li>Spinach</li>
</ul>
</li>
</ul>
Result: Two top-level bulleted items, "Fruits" and "Vegetables", each followed by its own further-indented sub-list of two bulleted items (Apple/Banana under Fruits, Carrot/Spinach under Vegetables).
Notice that the nested <ul> is placed inside the <li> it belongs to, not after it as a sibling of the outer <ul>. This is the only valid way to nest lists in HTML, and it produces a proper hierarchical DOM tree: the sub-list is a descendant of "Fruits", which is exactly what it conceptually is.
Example 3: A list used for navigation links
<nav>
<ul>
<li><a href="/">Home</a></li>
<li><a href="/courses">Courses</a></li>
<li><a href="/about">About</a></li>
<li><a href="/contact">Contact</a></li>
</ul>
</nav>
Result: Four bulleted, clickable text links stacked vertically — Home, Courses, About, and Contact — each navigating to a different page when clicked.
This pattern — a <ul> full of links, each wrapped in its own <li> — is how the vast majority of website navigation menus are built in HTML. Wrapping the whole thing in a <nav> landmark element tells assistive technology that this list specifically represents site navigation, not just a generic bulleted list. The bullets and horizontal layout you see in real-world menus come entirely from CSS layered on top of this same underlying markup.
How the Browser Builds the List (Under the Hood)
When the HTML parser encounters a list, it works through a predictable sequence:
- It reads the
<ul>start tag and creates a list container node in the DOM. - For each
<li>start tag, it creates a new list-item node as a child of the<ul>. - Because the closing
</li>tag is technically optional in the HTML parsing rules, if the parser hits a new<li>or the closing</ul>while a previous<li>is still "open," it automatically closes the previous one first. This is an error-recovery rule, not something you should rely on — always write your own closing tags for clarity and maintainability. - Once the DOM tree is built, the browser’s default (user-agent) stylesheet applies
display: list-itemto each<li>, which generates an implicit::markerpseudo-element containing the bullet. - The layout engine then applies default indentation (padding on the list) and stacks each item vertically, one per line.
Accessibility tools also rely on this structure: a screen reader that encounters a properly marked-up <ul> will typically announce "list, 3 items" before reading the contents, and announce each item’s position, such as "item 2 of 3." This only works correctly when the list is built from real <ul>/<li> markup — visually indenting text with CSS alone gives sighted users the appearance of a list without giving assistive technology any of that structural information.
Common Mistakes
Mistake 1: Putting content directly inside <ul> without <li>
<ul>
Milk
Eggs
Bread
</ul>
This is invalid: the only content model <ul> permits as direct children is <li> elements (plus a couple of rare script-support elements). Loose text directly inside a <ul> is a well-formedness error, and browsers will attempt to recover in inconsistent ways, while screen readers may fail to announce the list at all. The fix is to wrap every piece of content in its own <li>:
<ul>
<li>Milk</li>
<li>Eggs</li>
<li>Bread</li>
</ul>
Mistake 2: Nesting a sub-list as a sibling instead of a child
<ul>
<li>Fruits</li>
<ul>
<li>Apple</li>
</ul>
</ul>
Here the nested <ul> is placed directly inside the outer <ul>, as a sibling of the <li>, rather than inside the <li> it logically belongs under. Since <ul> only accepts <li> children, this is invalid nesting and misrepresents the relationship between "Fruits" and "Apple." The corrected version moves the sub-list inside the parent item:
<ul>
<li>Fruits
<ul>
<li>Apple</li>
</ul>
</li>
</ul>
Best Practices
- Use
<ul>only when the order of items truly doesn’t matter; if sequence or ranking matters (steps, rankings, instructions), use<ol>instead. - Always place a nested list inside the
<li>it belongs to, never as a sibling of the parent<ul>. - Write explicit closing
</li>tags even though HTML parsing allows you to omit them — it keeps markup readable and prevents subtle bugs when editing later. - Control bullet appearance with CSS (
list-style-type, the::markerpseudo-element) rather than the obsoletetypeattribute. - Wrap navigation lists in a
<nav>element so assistive technology recognizes the list as a navigation landmark. - Don’t reach for a list just to get bullet-point spacing on a single, unrelated block of text — reserve
<ul>for genuine collections of related items. - Keep list items parallel in structure and length where possible; a list mixing full sentences with single words is harder to scan.
Practice Exercises
- Build an unordered list of your three favorite books, with each title as its own list item.
- Build a two-level nested list: a top-level item called "Continents" containing at least two continent names, and under at least one continent, a nested list of two countries.
- Build a simple site navigation menu: a
<nav>element containing a<ul>with four<li>items, each holding an<a>link to a different page.
Summary
<ul>is the container for an unordered (bullet) list;<li>defines each list item, and is the only element<ul>may directly contain.- By default, browsers indent list items and precede each with a disc bullet, but this visual style is presentational and can be fully controlled with CSS.
- Sub-lists must be nested inside the
<li>they belong to, not placed as a sibling of the parent list. - Screen readers announce list structure (item count, position) only when real
<ul>/<li>markup is used, not when a list is faked with CSS indentation alone. - Navigation menus are commonly built from a
<ul>of links wrapped in a<nav>landmark. - Prefer
<ol>instead of<ul>whenever the order of items is meaningful.
