Creating Custom List Styles

Bulleted lists on the web come with default styles. When we create an unordered list which uses a <ul> element, the bullet is a disk whose color matches our text color. We can customize it a little bit, and make the bullet a circle or square, but we are pretty restricted. What if we wanted to use emojis instead? Let's take a look at how we would create that.

First let's create a list (Listing 1). We are going to list out the planets in our solar system.

List of planets
<ul>
  <li>Mercury</li>
  <li>Venus</li>
  <li>Earth</li>
  ...
</ul>

Since we haven't applied any styles to it yet, each list item is prefixed with a disk as seen in Figure 1.

Screenshot of the un-styled list with default bullet points as generated by the user agent stylesheet.
List default styles

list-style-type

To change the type of bullet being used our list we use thelist-style-type property. As its name implies, this property changes the type of bullet we want displayed in our list. One of the default values available is square, which we can apply to our list with the following rule: ul { list-style-type: square }. Our bullet points will now be square instead of round which we can see in Figure 2.

Screenshot of our list with the square list-style-type applied. The counters are now square
List with square counters

Accessibility Note

We can set our unordered list to use numbers as our bullets instead of a using the list-style-type property however assistive technologies will still be presented with an unordered list html element and present it as such. It is important to understand that this property only changes the display of the counter and not the nature of the list.

To create our custom bullets, we will define a list type, and then apply it to the list-style-type property the same way we do with the default options provided by CSS.

Defining the list style

To define what our bullet will look like, we will use the @counter-style at-rule. We have a pseudo-element (:marker) available to customize the bullet, but it does not allow us to change the type. In order to apply a custom symbol, we will need to use the @counter-style at-rule

At-rules allow use to define how our CSS should behave or set conditions for when it should be applied. The @counter-style at-rule lets us define our bullets' behavior. It tracks the position of the element inside of the list (hence it being called a counter, it counts), to apply custom styles and behavior.

The first thing we need to do is give our counter-style a name. We will call ours space. This is the property value we will pass to the list-style-type property once our counter-style is defined. Our at rule will therefore be @counter-style space { };

Inside of our at-rule we will use 3 properties to tell the browser what to do: symbols, system, and suffix.

Symbols

To define which emojis we want to replace the bullets with, we use the symbols property. We will pass it 4 emojis: 🪐 🚀 👩‍🚀 and ⭐.

We can either use the emoji itself like we did in Figure 2 or use the unicode value. If we were using the unicode values we would write our symbols declaration like so: symbols: "\1fa90" "\1f680" "\1f469 \200d \1f680" \2b50; as a space delimited list.

Notice that our 3rd emoji, the female astronaut (👩‍🚀) is compose of three values: "\1f469 \200d \1f680". This is because the emoji itself is 2 emojis put together to define the final glyph: the woman (👩), a 0 space joiner (\200d), and the rocket (🚀). In other words female astronaut = woman + rocket.

Defining our symbols
  @counter-style space {
    symbols: 🪐 🚀 👩‍🚀 ⭐;
  }

System

Next we define our system. The system property defines how we want the emojis to be applied to each list item. We will use cyclic which tells the browser to loop through the symbols as it loops through the list items. The first item will get a 🪐, the second the 🚀 and so on. Using cyclic when it runs out (after the 4th list-item), it will start back at the beginning of the list of symbols. Our fifth list item with therefore also get a 🪐.

Let's apply our space counter-style to our list and see what we look like. At this point our CSS looks as follows (Listing 3):

Defining our symbols
@counter-style space {
  symbols: 🪐 🚀 👩‍🚀 ⭐;
  system: cyclic;
}
ul { list-style-type: space }

Figure 3 shows our output.

Screenshot of our list with the emojis being used as counters
List with emoji counters

Our list now uses our emojis and correctly loops back to the beginning when it runs out. There is a period after the emoji though, which doesn't look awesome so we are going to remove it.

Suffix

The suffix property defines what comes after the bullet (our emoji). By default it's a period. We are going to change that to be a single white space character. Inside of the counter-style at-rule we will therefore add: suffix: " ";. With this declaration added, our finished list style (shown in Figure 4) is finished.

Screenshot of finished custom list style without periods after the emojis.
Space custom list style

Summary

All put together our final CSS is (Listing 4):

Defining our symbols
@counter-style space {
  symbols: 🪐 🚀 👩‍🚀 ⭐;
  system: cyclic;
  suffix: " ";
}
ul { list-style-type: space }

To create the custom bullets we:

  1. Created and named our @counter-style at-rule
  2. Defined the look and behavior of the list
  3. Applied the counter-style's name to the list-property-type of the list

The code is available below or on codepen at https://codepen.io/martine-dowden/pen/BaYVvjE?editors=1100.

Happy coding!

Consulting

Our expertise helps your team ramp up on new technologies or practices, or to fill short-term skills gaps.

Read more about Consulting with Andromeda