Styling numbered lists with CSS counters
Tags: css, tutorial
Published: 2020-05-28 15:18:27

---
title: Styling numbered lists with CSS counters
published: true
date: 2020-05-12 13:00:29 UTC
tags: css, tutorial
canonical_url: https://blog.logrocket.com/styling-numbered-lists-with-css-counters/
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/9xdvn4a5e3m044s38372.png
---
**Written by [Supun Kavinda](https://blog.logrocket.com/author/supunkavinda/)**✏️

In web design, it’s important to represent data in an organized way so that the user can easily understand the structure of the website or content. The simplest way to do this is to use ordered lists.

If you need more control over the appearance of the numbers, you might assume that you’d need to add more elements to the DOM via HTML or JavaScript and style them. Fortunately, CSS counters save you much of that trouble.

In this tutorial, we’ll demonstrate how to get started with CSS counters and go over some use cases.

## The problem with ordered lists

When you write an ordered list like the one below, the browser automatically renders the numbers for you.

```jsx
<ol>
  <li>My First Item</li>
  <li>My Second Item</li>
  <li>My Third Item</li>
</ol>
```

![Ordered List With No Style](https://i2.wp.com/blog.logrocket.com/wp-content/uploads/2020/05/ordered-list-no-style.png?resize=172%2C76&ssl=1)

This is great, but it doesn’t allow you to style the numbers. For example, let’s say you need to place the number inside a circle. How would you do that?

One way is to get rid of the list altogether and manually add numbers yourself.

```jsx
<div>
  <span>1</span> My First Item
</div>
<div>
  <span>2</span> My Second Item
</div>
<div>
  <span>3</span> My Third Item
</div>


div {
  margin-bottom:10px;
}
div span {
  display:inline-flex;
  align-items:center;
  justify-content:center;
  width:25px;
  height:25px;
  border-radius:50%;
  background-color:#000;
  color:#fff;
}
```

![Ordered List With Numbers in Circles](https://i0.wp.com/blog.logrocket.com/wp-content/uploads/2020/05/ordered-list-numbers-in-circle.png?resize=161%2C105&ssl=1)

This does what we need it to do, but there are some drawbacks. For one thing, it’s hard to write the numbers by hand. And what if you need to change a number? You’d have to change them all one by one. You could add the `<span>` element dynamically using JavaScript to address these problems, but this would add more nodes to the DOM, which leads to heavy memory usage.

In most cases, it’s better to use CSS counters. Let’s examine why.

[![LogRocket Free Trial Banner](https://i0.wp.com/blog.logrocket.com/wp-content/uploads/2017/03/f760c-1gpjapknnuyhu8esa3z0jga.png?resize=1200%2C280&ssl=1)](https://logrocket.com/signup/)

## Introduction to CSS counters

CSS counters are webpage-scope variables whose values can be changed using CSS rules.

First, set a counter using the `counter-reset` property. `list-number` is the variable name to use here.

```jsx
div.list {
  counter-reset: list-number;
}
```

Next, use the `counter-increment` property to increase the value of the counter.

```jsx
div.list div {
  counter-increment: list-number;
}
```

Now each time a `div.list div` element appears, the `list-number` variable increases by one.

Finally, use the `:before` pseudo-element with the `content` property and `counter()` function to display the number.

```jsx
div.list div:before {
  content: counter(list-number);
}
```

Here’s the full code:

```jsx
<div class="list">
  <div>My first item</div>
  <div>My second item</div>
  <div>My third item</div>
</div>


div.list {
  counter-reset: list-number;
}
/** Note that we can use counter-increment in :before psuedo element **/
div.list div:before {
  counter-increment: list-number;
  content: counter(list-number);
}
```

The output would look like this:

![](https://paper-attachments.dropbox.com/s_422C77841275E4B944A7E14EEE4D7C9DE7A7AAD71209E06BC6DD8C77460F4CCF_1587515686716_file.png)

We’re not quite there yet. Let’s style the `:before` pseudo-element to make it look better.

```jsx
div.list div:before {
  counter-increment: list-number;
  content: counter(list-number);
  
  margin-right: 10px;
  margin-bottom:10px;
  width:35px;
  height:35px;
  display:inline-flex;
  align-items:center;
  justify-content: center;
  font-size:16px;
  background-color:#d7385e;
  border-radius:50%;
  color:#fff;
}
```

{% codepen https://codepen.io/SupunKavinda/pen/OJybvoq %}

## Changing the starting point

By default, `counter-reset` sets the counter to `0`. It starts from `1` after the first `counter-increment` call. Set the initial value by passing an integer as the second parameter to the `counter-reset` function.

```jsx
div.list {
  counter-reset: list-number 1;
}
```

![Ordered List Styled With counter-reset](https://i2.wp.com/blog.logrocket.com/wp-content/uploads/2020/05/ordered-list-counter-reset.png?resize=604%2C286&ssl=1)

If you want to start from `0`, set the initial value to `-1`.

```jsx
div.list {
  counter-reset: list-number -1;
}
```

![Ordered List With counter-reset From Zero](https://i0.wp.com/blog.logrocket.com/wp-content/uploads/2020/05/ordered-list-counter-reset-from-zero.png?resize=542%2C271&ssl=1)

## Changing incremental values

By default, `counter-increment` increases the value of the counter by one. Just like `counter-reset`, you can define an offset for the `counter-increment` property.

In this example, `counter-reset` sets `list-number` to `0`. Each time the `counter-increment` is called, the value of `list-number` increases by `2`, so, you’ll see numbers as `2`, `4`, and `6`.

```jsx
div.list {
  counter-reset: list-number;
}
div.list div:before {
  counter-increment: list-number 2;
  // other styles
}
```

![Styled Ordered List With counter-increment](https://i2.wp.com/blog.logrocket.com/wp-content/uploads/2020/05/ordered-list-counter-increment.png?resize=600%2C280&ssl=1)

## Counter formats

The `counter()` function can have two parameters: `counter-name` and `counter-format`. For the second parameter, you can use any [valid list-style-type value](https://www.w3schools.com/cssref/pr_list-style-type.asp), including:

- `decimal` (e.g., 1, 2, 3…)
- `lower-latin` (e.g., a, b, c…)
- `lower-roman` (e.g., i, ii, iii…)

The default value is `decimal`.

For example, if you love science like me, you can use `lower-greek` for alpha-beta value numbering.

```jsx
div.list div:before {
  counter-increment: list-number;
  content: counter(list-number, lower-greek);
  // ... other styles
}
```

![Ordered List With Greek Characters Styled With CSS Counters](https://i1.wp.com/blog.logrocket.com/wp-content/uploads/2020/05/ordered-list-greek-characters.png?resize=539%2C273&ssl=1)

## Nested counters

When using nested ordered lists, numbering is always shown in this format:

![](https://paper-attachments.dropbox.com/s_422C77841275E4B944A7E14EEE4D7C9DE7A7AAD71209E06BC6DD8C77460F4CCF_1587519748833_file.png)

If you need numbers for child list items (e.g.,`1.1`), you can use CSS counters with the `counters()` function.

```jsx
<ol>
  <li>
     My First Item
    <ol>
      <li>My Nested First Item</li>
      <li>My Nested Second Item</li>
    </ol>
  </li>
  <li>My Second Item</li>
</ol>


ol {
  list-style-type:none;
  counter-reset:list;
}
ol li:before {
    counter-increment:list;
    content: counters(list, ".") ". ";
}
```

![](https://paper-attachments.dropbox.com/s_422C77841275E4B944A7E14EEE4D7C9DE7A7AAD71209E06BC6DD8C77460F4CCF_1587519954505_file.png)

Note that we’re using the `counters()` function, not `counter()`.

The second parameter of the `counters()` function is the connection string. It can also have a third parameter to set the format (e.g., Greek or Roman).

### Nested counters with headings

Elements such as `<h1>`, `<h2>` are not nested in a document. They appear as distinct elements but still represent a sort of hierarchy. Here’s how to prepend nested numbers to headings:

```jsx
body {
  counter-reset:h1;
}
h1 {
  counter-reset:h2;
}
h1:before {
  counter-increment: h1;
  content: counter(h1) ". ";
}
h2:before {
  counter-increment:h2;
  content: counter(h1) "." counter(h2) ". ";
}
```

The `h2` counter resets every time an `h1` is found. Each `<h2>` in the document gets a number like `x.y.` relative to the `<h1>`.

## Browser support

Thankfully, CSS counters are widely supported by browsers since they were introduced with CSS2. While using the `counter()` function in properties other than `content` is still experimental, you can do all the exercises we covered in this tutorial without any hesitation.

Below are browser support details from [Can I use](http://caniuse.com).

![Browser Support for CSS Counters](https://i2.wp.com/blog.logrocket.com/wp-content/uploads/2020/05/css-counters-browser-support.png?resize=720%2C254&ssl=1)

## A simple challenge

Are you ready for a simple challenge involving CSS counters?

Display `1` through `1000`, along with their Roman characters, in 10 lines of code using CSS counters.

If you’re stumped, here’s how you do it:

To create 1,000 `div` elements, use the following.

```jsx
for (var i = 0; i < 1000; i++) {
  document.body.appendChild( document.createElement("div") );  
}
```

CSS counters:

```jsx
body {
  counter-reset:number;
}
div:before {
  counter-increment:number;
  content: counter(number) " => " counter(number, lower-roman);
}
```

{% codepen https://codepen.io/SupunKavinda/pen/MWabGZQ %}

What did you come up with?

## Conclusion

CSS counters are a lesser-known feature in CSS, but you’d be surprised how often they come in handy. In this tutorial, we covered how and when to use CSS counters and went over some examples.

Below is a list of the properties we used.

<table>
<tbody>
<tr>
<td style="text-align: center;"><strong>Property</strong></td>
<td style="text-align: center;"><strong>Usage</strong></td>
</tr>
<tr>
<td><code class=" prettyprinted" style=""><span class="pln">counter</span><span class="pun">-</span><span class="pln">reset</span></code></td>
<td>Reset (or create) a counter to given value (default 0)</td>
</tr>
<tr>
<td><code class=" prettyprinted" style=""><span class="pln">counter</span><span class="pun">-</span><span class="pln">increment</span></code></td>
<td>Increase a given counter by given offset (default 1)</td>
</tr>
<tr>
<td><code class=" prettyprinted" style=""><span class="pln">counter</span><span class="pun">(</span><span class="pln">counter</span><span class="pun">-</span><span class="pln">name</span><span class="pun">,</span><span class="pln"> counter</span><span class="pun">-</span><span class="pln">format</span><span class="pun">)</span></code></td>
<td>Get the value of the counter from the given format</td>
</tr>
<tr>
<td><code class=" prettyprinted" style=""><span class="pln">counters</span><span class="pun">(</span><span class="pln">counter</span><span class="pun">-</span><span class="pln">name</span><span class="pun">,</span><span class="pln"> counter</span><span class="pun">-</span><span class="kwd">string</span><span class="pun">,</span><span class="pln"> counter</span><span class="pun">-</span><span class="pln">format</span><span class="pun">)</span></code></td>
<td>Get value of nested counters from the given format</td>
</tr>
</tbody>
</table>

Of course, CSS counters are cool. But one thing I’m concerned about is that all counters are global. If you use many of them on a large project that has many CSS files, you may not be able to find where they are created, reset, and incremented. Don’t overuse them if you can help it, and if you must, be sure to use descriptive names for counters to avoid conflicts.

* * *
## Is your frontend hogging your users' CPU?

As web frontends get increasingly complex, resource-greedy features demand more and more from the browser. If you’re interested in monitoring and tracking client-side CPU usage, memory usage, and more for all of your users in production, [try LogRocket.](https://logrocket.com/signup/) 

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/403rye2ptzx994uhktk1.png)

[LogRocket](https://logrocket.com/signup/) is like a DVR for web apps, recording everything that happens in your web app or site. Instead of guessing why problems happen, you can aggregate and report on key frontend performance metrics, replay user sessions along with application state, log network requests, and automatically surface all errors.

Modernize how you debug web apps — [Start monitoring for free.](https://logrocket.com/signup/)
* * *

The post [Styling numbered lists with CSS counters](https://blog.logrocket.com/styling-numbered-lists-with-css-counters/) appeared first on [LogRocket Blog](https://blog.logrocket.com).