HTML Unordered Lists Guide

Organizing Information with Bullet Points

Not everything on a webpage fits naturally into a paragraph - sometimes you've got a bunch of related things that just need to exist as a list, and trying to force them into flowing prose makes both the writing and the reading worse for everyone involved. The ul tag is what HTML gives you for exactly this situation: a collection of items where the order doesn't matter, presented with bullet points by default. Navigation menus, feature lists, ingredient lists, a set of requirements - any time you have a group of related items that aren't ranked or sequential, that's a ul and if you've been writing asterisks into paragraphs or using br tags to fake the visual effect, this section is specifically for you. I did that too for longer than I want to admit.

What are ul and li Tags?

The unordered list is built from two tags that always work together - the ul which is the outer container for the whole list, and the li which wraps each individual item inside it - and you genuinely cannot use one without the other in valid HTML. The ul tag tells the browser that what follows is an unordered list, meaning the items belong together as a group but their sequence isn't significant. Each li is one item in that list. That's really the whole structure and it's one of the more intuitive tag relationships in HTML once you see it.

html
1<ul>
2  <li>First item</li>
3  <li>Second item</li>
4  <li>Third item</li>
5</ul>

Key Components

  • Container - The ul tag wraps the entire list and signals to browsers and assistive technology that the items inside form a related group.
  • Items - Every single item in the list must be wrapped in its own li tag - you can't just put text directly inside ul.
  • Structure - The only valid direct children inside a ul are li elements. Putting other tags directly inside ul without li wrappers is invalid HTML.

Why Use Unordered Lists? Beyond Simple Bullets

The visual difference between a ul and just typing asterisks before some text is basically nothing to a sighted user - both look like bullet points - but the semantic difference is significant and affects three things that actually matter: accessibility, search engines, and CSS. Screen readers announce to users when they're entering a list and how many items it contains, so a user navigating by screen reader knows they're about to encounter a group of four related items rather than just hitting random text - that context is genuinely useful and you can only provide it with a proper ul. Search engines use list structure to understand how items on your page relate to each other, which feeds into how they categorize and rank your content. And from a styling perspective, having a proper ul gives you clean CSS hooks - you can target ul li and style every list item on your whole site from one rule, rather than hunting down whatever classes or elements you slapped asterisks next to.

Benefits

  • Semantic Structure - The ul tag communicates to browsers, search engines, and assistive technology that these items belong together as a logical group.
  • Accessibility - Screen readers announce the list and item count to users, giving context that plain text or fake bullet points cannot provide.
  • Styling Control - Proper list elements give you reliable CSS hooks - you can target lists globally or specifically and the styling is predictable.
  • SEO - Structured list content helps search engines understand groupings and relationships between items on your page.

Creating Nested Lists

You can nest a new ul inside an li to create sub-lists, which is useful for categories with sub-items or any hierarchy where some items have children of their own - the classic example is a site navigation with dropdown sub-menus underneath main items. The nested ul goes inside the li, after whatever text that list item has, and browsers will automatically change the bullet style for each nesting level so you can visually tell the hierarchy apart. I used nested lists for the first time trying to build a navigation menu and the auto-indenting and different bullet styles felt almost too convenient, like the browser already knew what I was trying to do.

html
1<ul>
2  <li>Fruits
3    <ul>
4      <li>Apples</li>
5      <li>Oranges</li>
6    </ul>
7  </li>
8  <li>Vegetables
9    <ul>
10      <li>Broccoli</li>
11      <li>Carrots</li>
12    </ul>
13  </li>
14</ul>

Nesting Rules

  • Placement - The nested ul goes inside the li element, not after it - placing it outside the li breaks the structure and produces invalid HTML.
  • Visual Style - Browsers automatically use different bullet styles for each nesting level - disc at the top, then circle, then square - without you doing anything.
  • Depth - You can nest lists multiple levels deep but more than two or three levels usually hurts readability more than it helps organization.

Styling Unordered Lists with CSS

The default browser bullet - a solid black disc - is about as bare as it gets, and most real projects will override it completely. The list-style-type property lets you swap to circle, square, or none, and list-style-image lets you use an actual image file as the bullet. The most flexible approach that I see used in production code the most is to set list-style-type to none and then build your own bullet using the li::before pseudo-element in CSS - that way you have total control over the color, size, position, and character used as the marker, and you can use emoji or custom icons or checkmarks or anything else that fits the design.

html
1<style>
2  .custom-list {
3    list-style-type: none;
4    padding-left: 0;
5  }
6  .custom-list li {
7    padding-left: 2em;
8    position: relative;
9  }
10  .custom-list li::before {
11    content: "✓";
12    color: green;
13    font-weight: bold;
14    position: absolute;
15    left: 0;
16  }
17</style>
18
19<ul class="custom-list">
20  <li>24/7 Customer Support</li>
21  <li>Free Shipping</li>
22  <li>Lifetime Guarantee</li>
23</ul>

Styling Techniques

  • list-style-type - Changes the bullet marker - options include disc (default), circle, square, and none. Setting it to none removes bullets entirely so you can build your own.
  • list-style-image - Lets you use an image file as the bullet. Useful for branded bullet points but gives you less control over sizing than the pseudo-element approach.
  • li::before pseudo-element - The most flexible option - remove default bullets and inject custom content before each li using CSS. Full control over character, color, size, and position.

Best Practices for Using Unordered Lists

The main thing to get right with ul is using it for the right situations - it's for groups of related items where order genuinely doesn't matter, not for anything where sequence is important (that's what ol is for), and not for page layout (that's what CSS flexbox and grid are for). The direct children of a ul should only ever be li elements - putting divs or paragraphs directly inside a ul without li wrappers is technically invalid and browsers will handle it inconsistently. Keep your list items concise, make sure they make sense when read in isolation, and if a list is growing beyond about fifteen items seriously consider whether it should be broken into sub-lists or split across multiple sections with headings.

html
1<!-- Good: related items with no meaningful sequence -->
2<ul>
3  <li>24/7 Customer Support</li>
4  <li>Free Shipping</li>
5  <li>Lifetime Guarantee</li>
6</ul>
7
8<!-- Wrong: using lists for page layout -->
9<!-- Use CSS Flexbox or Grid for layout instead -->

Common Mistakes to Avoid

Using asterisks or hyphens typed directly into a paragraph instead of actual list elements is the most common one, and it's such a persistent habit because it looks fine visually and nothing technically breaks - but it's meaningless to a screen reader and a nightmare to style consistently with CSS. The other mistake worth knowing about is using deprecated HTML attributes like type or compact directly on the ul tag to style it - those attributes are no longer supported in HTML5 and any styling you want should go in your CSS file, not on the HTML element itself.

html
1<!-- Wrong: faking lists with typed characters -->
2* Item one<br>
3* Item two<br>
4* Item three
5
6<!-- Right: actual list elements -->
7<ul>
8  <li>Item one</li>
9  <li>Item two</li>
10  <li>Item three</li>
11</ul>

Mistakes to Watch For

  • Fake bullets - Using asterisks, hyphens, or br tags to visually simulate a list - looks fine on screen but has no semantic meaning and can't be styled as a unit.
  • Deprecated attributes - The type and compact attributes on ul are no longer valid in HTML5. All list styling should be done through CSS.
  • Layout misuse - Using ul for page layout instead of content grouping - lists aren't layout tools and using them that way creates accessibility and maintenance problems.

Your Tool for Grouped Ideas

The ul and li tags are genuinely one of the more satisfying HTML structures to use once you're in the habit because the semantic intent is so clear - this is a group of things that belong together, order doesn't matter - and browsers, screen readers, and search engines all understand that signal correctly. The CSS flexibility you get from proper list markup versus fake bullets is also pretty immediate and tangible once you try to style a page. Next up is the ordered list - ol - which is the same structure with the difference that sequence matters, so the items are numbered instead of bulleted and swapping two items would change the meaning

Frequently Asked Questions

Can I put other HTML elements inside an li tag?

Yes, and it's pretty common to do so. An li can contain inline elements like a, strong, em, and img without any issues. It can also contain block-level elements like p, div, or even another ul for nested lists. Where things go wrong is putting block-level elements directly inside the ul without wrapping them in li first - that's invalid HTML and browsers handle it unpredictably.

How do I remove the default indentation from a list?

The left indentation comes from the browser's default padding on the ul element. You can remove it with padding-left: 0 on the ul in your CSS. Just be aware that this also moves the bullet markers, which are positioned relative to that padding, so they might appear outside the element or get clipped. The usual fix is to remove the default bullets entirely with list-style-type: none and then build your own spacing and markers from scratch using li padding and the ::before pseudo-element.

What is the difference between list-style-type none and just using a div?

Even with no visible bullets, a ul with list-style-type: none is still semantically a list - screen readers will still announce it as a list with a count of items, which is the accessible behavior you want. If you replace the ul with a div to get the same visual result, you strip out all that semantic information and users navigating by screen reader lose the context that they're in a grouped collection of items. The right approach is always to use the semantically correct element and then style it however the design requires.

How many items should I put in a single list?

There's no hard rule but somewhere beyond ten to fifteen items most lists start becoming hard to scan and process in one go. If you're getting that long, ask whether the items could be grouped into categories with sub-lists, or whether the list should be split into multiple shorter lists each under their own heading. Very long flat lists tend to feel overwhelming and users often stop reading partway through.

When should I use ul versus ol?

Use ul when the order of the items genuinely doesn't matter - a list of features, a set of ingredients, a collection of links. Use ol when the sequence is part of the meaning - steps in a recipe, ranked results, installation instructions where step 3 depends on step 2. If you could reorder the items and nothing important changes, it's a ul. If reordering would confuse or break the meaning, it's an ol.

Can I use a ul for a navigation menu?

Yes, and this is actually the standard semantic approach - most navigation menus on the web are built with a nav element containing a ul with li items, each li containing an anchor tag. The list structure makes sense because a set of navigation links is semantically a group of related items with no required sequence. You then use CSS to hide the bullets and style the links however the design requires. Using list-style-type: none on a nav ul is so common it's basically boilerplate.