Skip to main content
Ben Nadel at InVision In Real Life (IRL) 2019 (Phoenix, AZ) with: Matt Borgato
Ben Nadel at InVision In Real Life (IRL) 2019 (Phoenix, AZ) with: Matt Borgato

Using CSS Counters To Apply Custom Labels To An HTML List

By
Published in

The other day, one of my teammates, Hector Yeomans, shared a blog post by Nicolas Carlo on the Strangler Pattern. The post, in and of itself, was an intriguing look at how to avoid "big bang" rewrites. However, as I was reading the post, something else caught my eye. Nicolas was doing something that I had never seen before: he was styling his Ordered List labels using CSS Counters. I had never heard of CSS Counters before; so, I wanted to try them out for myself.

Run this demo in my JavaScript Demos project on GitHub.

View this code in my JavaScript Demos project on GitHub.

CSS Counters provide a way to adjust the appearance of content based on where it is located within the HTML document. Ordered List Items already do this for us, providing an auto-incrementing index. CSS Counters give us the kind of functionality; however, we can apply counters across all sorts of elements, not just lists.

Considering that the browser support for CSS Counters goes all the way back to IE8, I'm somewhat shocked that I've never heard of this before! But, my CSS skills have always been a bit lacking; so, I'm not all that surprised.

Since this is my first look at CSS Counters - this post is essentially one big note to self - I'm not going to get into too many details. But, the fundamental CSS Counter mechanics revolve around resetting, incrementing, and then reading values:

  • counter-reset: name [ default ] - This resets the given counter to 0 by default.

  • counter-increment: name [ delta ] - This increments the given counter by 1 by default.

  • counter( name [ , format ] ) - This reads the current counter value.

There's more to it than that, especially when you get into nested lists. But, this is all that I understand for the moment.

To try this out for myself, I've created a list of Friends that includes a stylized list item label. The label is created using the ::before pseudo-element; and, its content is generated using the counter() function:

<!doctype html>
<html>
<head>
	<meta charset="utf-8" />

	<title>
		Using CSS Counters To Apply Custom Labels To An HTML List
	</title>
</head>
<body>

	<h1>
		Using CSS Counters To Apply Custom Labels To An HTML List
	</h1>

	<style type="text/css">

		ul.friends {
			/*
				Start a new counter whose default value is 0.
				// --
				NOTE: It appears that if you want to use a counter across several sibling
				elements (such as across multiple UL elements), the counter has to be
				reset at a higher level in the DOM (such as Body, Section, etc).
			*/
			counter-reset: friends ;
			/* -- */
			font-size: 26px ;
			list-style-type: none ;
			margin: 20px 0px 20px 15px ;
			padding: 0px 0px 0px 0px ;
		}

		ul.friends li {
			/* Increment the counter by 1. */
			counter-increment: friends ;
			/* -- */
			align-items: center ;
			display: flex ;
			margin: 5px 0px 5px 0px ;
			padding: 0px 0px 0px 0px ;
		}

		ul.friends li::before {
			/*
				Use the current counter value to set the content of the pseudo-element.
				--
				CAUTION: Use of counter() in anything other than "content" is considered
				to be experimental.
			*/
			content: counter( friends ) ;
			/* -- */
			background-color: #eaeaea ;
			border-radius: 5px 5px 5px 5px ;
			box-sizing: border-box ;
			flex: 0 0 auto ;
			font-family: monospace ;
			font-size: 14px ;
			line-height: 25px ;
			margin-right: 10px ;
			min-width: 35px ;
			padding: 0px 5px 0px 5px ;
			text-align: center ;
		}

		ul.friends li.bff::before {
			background-color: #ff3366 ;
			color: #ffffff ;
		}

	</style>

	<ul class="friends">
		<li class="bff">Kim</li>
		<li>Danny</li>
		<li>Sarah</li>
		<li class="bff">Luke</li>
		<li>Hanah</li>
		<li>Timmy</li>
		<li>Henry</li>
		<li>Cindi</li>
		<li>Donna</li>
		<li>Benji</li>
		<li class="bff">Carl</li>
		<li>Nancy</li>
	</ul>

</body>
</html>

As you can see, at the ul level, I'm initializing my CSS Counter using counter-reset. Then, at each li, I'm incrementing the CSS Counter using counter-increment. And, finally, in the ::before pseudo-element, I'm applying the counter value to the DOM (Document Object Model) using counter(). And, when we run the above page, we get the following browser output:

CSS Counters being used to add custom styling to a list item label in HTML.

As you can see, the list of friends has completely customized labels. And, we didn't need to apply any fancy JavaScript or keep track of an external value. It's all just CSS!

Such fun! Much wow!

I'm certain I'll be making use of CSS Counters. In the past, I've achieved similar things in my Angular apps by applying $index values in my ng-for loops. But, with CSS Counters, not only does this become easier, it becomes doable outside of any dynamically-rendered, JavaScript-driven content.

Want to use code from this post? Check out the license.

Reader Comments

I believe in love. I believe in compassion. I believe in human rights. I believe that we can afford to give more of these gifts to the world around us because it costs us nothing to be decent and kind and understanding. And, I want you to know that when you land on this site, you are accepted for who you are, no matter how you identify, what truths you live, or whatever kind of goofy shit makes you feel alive! Rock on with your bad self!
Ben Nadel