HTML Ordered Lists

Ordered Lists Overview

The difference between an ordered list and an unordered list is one letter in the tag name - ol instead of ul - but semantically they're saying something quite different. A ul says these items belong together as a group. An ol says these items belong together and their sequence matters - reordering them would change or break the meaning. Step 3 of an assembly process only makes sense after step 2. The third-place finisher in a ranking means something different from the first. That sequential meaning is baked into the ol element, and browsers, screen readers, and search engines all read it that way.

Key Components

  • <ol> - The container element for the entire ordered list. Browsers automatically number the items inside it starting from 1 by default.
  • <li> - Each individual item in the list. Same tag as unordered lists - the numbering comes from being inside an ol rather than a ul.

Basic Syntax

The syntax for an ordered list is identical to an unordered list except the outer tag is ol instead of ul - and the browser handles all the numbering automatically, which is the whole point of using it instead of manually typing 1, 2, 3 into your HTML.

html
1<ol>
2  <li>Preheat oven to 350°F (175°C)</li>
3  <li>Grease and flour a cake pan</li>
4  <li>Mix dry ingredients in a bowl</li>
5  <li>Add wet ingredients and mix until combined</li>
6  <li>Pour batter into the prepared pan</li>
7  <li>Bake for 30-35 minutes</li>
8</ol>

Browser Output

  • 1. - Preheat oven to 350°F (175°C)
  • 2. - Grease and flour a cake pan
  • 3. - Mix dry ingredients in a bowl

The type Attribute

The type attribute on an ol element changes what kind of marker is used for each item - you're not limited to plain numbers, which is useful for document outlines where you want letters or roman numerals for different sections. One thing worth knowing is that the CSS list-style-type property does the same job and is generally preferable for new code since it keeps styling separate from HTML, but the type attribute is still valid HTML5 and useful for quick cases.

html
1<ol type="A">
2  <li>Introduction</li>
3  <li>Main Content</li>
4  <li>Conclusion</li>
5</ol>

Numbering Options

  • type="1" - Decimal numbers: 1, 2, 3, 4 - the default.
  • type="A" - Uppercase letters: A, B, C, D - useful for main sections in a document outline.
  • type="a" - Lowercase letters: a, b, c, d - often used for sub-sections.
  • type="I" - Uppercase Roman numerals: I, II, III, IV - common in legal and formal documents.
  • type="i" - Lowercase Roman numerals: i, ii, iii, iv - often used for introductory pages or sub-items.

The start Attribute

The start attribute lets you specify which number the list should begin counting from, which sounds niche but is genuinely useful when you need to split a numbered sequence across sections of a page with other content in between - without start you'd have to manually override the value attribute on individual li elements or use CSS counters, both of which are more work.

html
1<ol start="5">
2  <li>Fifth item</li>
3  <li>Sixth item</li>
4  <li>Seventh item</li>
5</ol>

Browser Output

  • 5. - Fifth item
  • 6. - Sixth item
  • 7. - Seventh item

The reversed Attribute

The reversed attribute makes the list count down instead of up, so a three-item list would show 3, 2, 1 instead of 1, 2, 3 - the main use case is countdown rankings where the last item revealed is the winner, like a top-10 list that builds suspense. It's a boolean attribute so you just write reversed with no value, the same way you'd write disabled on a button.

html
1<ol reversed>
2  <li>Third place</li>
3  <li>Second place</li>
4  <li>First place</li>
5</ol>

Nested Ordered Lists

You can put an ol inside an li to create sub-steps within a larger step - useful for complex instructions where a main step has several sub-steps that need their own sequence. Browsers automatically use different numbering for nested levels if you set the type attribute on the inner list, otherwise they'll both use numbers which can look confusing, so it's worth changing the inner list type to lowercase letters or roman numerals to visually distinguish the levels.

html
1<ol>
2  <li>Preheat the oven
3    <ol type="a">
4      <li>Set temperature to 350°F</li>
5      <li>Allow 10 minutes for preheating</li>
6    </ol>
7  </li>
8  <li>Prepare ingredients
9    <ol type="a">
10      <li>Measure flour</li>
11      <li>Crack eggs into a separate bowl</li>
12    </ol>
13  </li>
14</ol>

CSS Styling Basics

The list-style-type CSS property on an ol element controls the marker type the same way the type attribute does, but it's the preferred approach for new code because styling belongs in CSS rather than HTML. You can also use list-style-position to control whether the marker sits inside or outside the list item's content box, which affects how wrapped text aligns.

css
1/* Change marker type via CSS instead of the type attribute */
2ol {
3  list-style-type: upper-roman;
4}
5
6/* Control marker position */
7ol {
8  list-style-position: inside; /* or outside (default) */
9}
10
11/* Remove default spacing */
12ol {
13  padding-left: 1.5em;
14  margin: 0;
15}

Custom CSS Counters

CSS counters give you complete control over the numbering display - you can prefix the number with custom text like 'Step 1:' or 'Phase 2.', change the color, weight, and size independently from the list item text, and create more complex counter patterns. The pattern is: reset the counter on the ol, increment it on each li, and display it using the ::before pseudo-element with the counter() function. I used this technique for the first time on a tutorial page and it made the steps look noticeably more designed than the default numbers - worth knowing even if it takes a few minutes to wrap your head around the counter-reset and counter-increment properties.

html
1<style>
2  .custom-ol {
3    list-style-type: none;
4    counter-reset: custom-counter;
5    padding-left: 0;
6  }
7  .custom-ol li {
8    counter-increment: custom-counter;
9    margin-bottom: 0.5em;
10    padding-left: 5em;
11    position: relative;
12  }
13  .custom-ol li::before {
14    content: "Step " counter(custom-counter) ": ";
15    color: #e74c3c;
16    font-weight: bold;
17    position: absolute;
18    left: 0;
19  }
20</style>
21
22<ol class="custom-ol">
23  <li>Gather your materials</li>
24  <li>Prepare your workspace</li>
25  <li>Begin the assembly process</li>
26</ol>

Best Practices

The most important rule for ordered lists is to only use them when the sequence genuinely matters - if you could reorder the items and nothing meaningful changes, it should be a ul instead. Keep list items grammatically parallel, meaning they all start with the same type of word (all imperatives like 'Click', 'Open', 'Select' for instructions, for example) which makes the list easier to scan. For styling, prefer CSS over HTML attributes. And when nesting, don't go deeper than two or three levels - nested lists beyond that tend to be hard to follow and usually signal that the content could be restructured more clearly.

Key Guidelines

  • Sequential content only - Only use ol when the order is genuinely meaningful - when reordering items would change or break what the list communicates.
  • Grammatical parallelism - Start each list item with the same grammatical form - all imperatives, all nouns, all gerunds. It makes lists much easier to scan.
  • CSS for styling - Use list-style-type in CSS rather than the type attribute on the ol element. Same effect, better separation of content and presentation.
  • Limit nesting depth - Two levels of nesting is usually the practical limit - three or more levels is hard for users to follow and often signals the information could be organized differently.

Common Mistakes

The most common mistake with ordered lists is typing the numbers manually into the HTML as plain text - which works visually but misses the entire point of using a semantic list element, and creates a maintenance nightmare if you ever need to insert, remove, or reorder steps because you have to manually renumber everything. The browser handles renumbering automatically when you use proper ol and li elements, so if you add a new step 3 everything after it shifts to 4, 5, 6 without you touching the other items.

html
1<!-- Wrong: manual numbering in plain text -->
21. First item<br>
32. Second item<br>
43. Third item
5
6<!-- Right: semantic HTML, browser handles the numbers -->
7<ol>
8  <li>First item</li>
9  <li>Second item</li>
10  <li>Third item</li>
11</ol>

When to Use Ordered Lists

The quick test for ol versus ul is: would changing the order break the meaning? Steps in a process, ranked items, numbered instructions - those are ol. Features of a product, a set of requirements, a list of links - those are ul. The visual difference after CSS is applied might be minimal but the semantic difference matters for screen readers and search engines that interpret the structure.

html
1<!-- Use ol: sequence matters, reordering breaks meaning -->
2<ol>
3  <li>Install the software</li>
4  <li>Run the setup wizard</li>
5  <li>Restart your computer</li>
6</ol>
7
8<!-- Use ul: sequence doesn't matter -->
9<ul>
10  <li>Unlimited storage</li>
11  <li>24/7 support</li>
12  <li>Free updates</li>
13</ul>

Ordered Lists: Sequence as Meaning

The ol element is one of those HTML tags where the choice between it and its alternative (ul) isn't arbitrary - it's a semantic statement about whether the order of your content carries meaning. Used correctly it gives you automatic numbering that updates when you add or remove items, accessibility benefits from screen readers announcing numbered steps, and a clear signal to search engines about procedural content. The attributes - type, start, reversed - are genuinely useful for the situations they're designed for, and the CSS counter approach gives you full design control when the default numbered style doesn't fit the visual treatment you're going for

Mixing List Types

You can nest a ul inside an ol or an ol inside a ul when the content structure calls for it - the most common case being a set of ordered main steps where each step has a collection of optional or parallel sub-items that don't have a required sequence, so the sub-items are a ul inside the li of the main ol. The nesting rules are the same regardless of which combination you use: the inner list always goes inside an li element, never directly inside the outer list tag.

html
1<ol>
2  <li>Set up your development environment
3    <ul>
4      <li>Install a code editor (VS Code, Sublime, etc.)</li>
5      <li>Install Node.js or your preferred runtime</li>
6      <li>Configure your terminal</li>
7    </ul>
8  </li>
9  <li>Clone the project repository</li>
10  <li>Install dependencies</li>
11</ol>

Continuing Numbering Across Sections

The start attribute is the straightforward solution for continuing a numbered sequence across two separate ol elements with content between them - the second list starts wherever you tell it to with start="5" or whatever the next number should be. This comes up on long tutorial pages where each major section has its own ol but you want the step numbers to run continuously across the whole page.

html
1<ol>
2  <li>First item</li>
3  <li>Second item</li>
4</ol>
5
6<p>Some explanatory content between the lists.</p>
7
8<ol start="3">
9  <li>Third item (continues from above)</li>
10  <li>Fourth item</li>
11</ol>

Frequently Asked Questions

Can I use custom images instead of numbers in an ordered list?

Not directly with standard list properties, but the CSS counter approach gets you there. Set list-style-type: none to remove the default numbers, then use the ::before pseudo-element with counter() to display the number however you want - you can add background images, icons, or custom formatting around the counter value. It's more CSS than most simple lists need but it gives you complete visual control.

Do search engines treat ordered lists differently from unordered lists?

Search engines understand the semantic difference between ol and ul and use it as a signal about the nature of your content - an ol suggests procedural or ranked content, a ul suggests a collection. This isn't a direct ranking factor but using the semantically correct element gives search engines more accurate context about your content, which feeds into how well it matches relevant queries. For step-by-step tutorials and how-to content specifically, proper ol markup can help your content appear in featured snippet results.

What is the value attribute on a li tag?

The value attribute on an individual li element overrides the automatic counter for that specific item and all subsequent items in the list. So if you have a five-item list and you put value="10" on the third item, the third item shows 10, the fourth shows 11, and the fifth shows 12. This is different from the start attribute which sets the starting number for the whole list - value lets you change the counter partway through, which comes up when you need to skip numbers or reset mid-list.

How do I remove the default left indentation from an ordered list?

The indentation comes from default padding-left set by the browser on the ol element, usually around 40px. You can override it with padding-left: 0 in your CSS, though this will also shift the number markers which are positioned relative to that padding. A common pattern is to set padding-left to a smaller value like 1.5em rather than zero, which keeps the numbers visible and properly aligned while reducing the overall indentation.

Can I style individual list items differently in an ordered list?

Yes - add a class to the li element you want to target and write a CSS rule for it. You can also use li:first-child and li:last-child to target the first and last items, or li:nth-child(n) to select specific items by position. If you want to highlight a particular step in a process - maybe the most important one or a warning step - adding a class to that li and giving it a different background color or border is a straightforward approach.