CSS has several ways to generate counters and markers, but some use cases require more control over how those markers are displayed.
The CSS symbols() function provides a way to define a custom counter style directly in CSS. Instead of relying only on predefined numbering styles such as decimal or lower-alpha, developers can define their own sequence of symbols.
This is useful for custom lists, navigation steps, labels, and other interfaces where the marker needs a specific visual pattern.
What Is symbols()?
The symbols() function defines a custom counter style.
A simple example is:
.steps {
list-style-type: symbols("One" "Two" "Three");
}
The list can then use the defined symbols as its markers.
For example:
<ol class="steps">
<li>Install the application</li>
<li>Configure the database</li>
<li>Start the application</li>
</ol>
Instead of normal numeric markers, the list uses the custom symbol sequence.
Basic Syntax
The general syntax is:
symbols(<symbol> <symbol> ...);
For example:
.steps {
list-style-type: symbols("Step A" "Step B" "Step C");
}
The symbols can be strings or other supported CSS symbol values.
The important point is that symbols() defines the counter style; it does not directly insert arbitrary text into the page like a pseudo-element.
A Practical Example
Consider a setup guide:
<ol class="setup">
<li>Create a project</li>
<li>Install dependencies</li>
<li>Configure the application</li>
<li>Run the project</li>
</ol>
You can create custom markers:
.setup {
list-style-type: symbols(
"Create"
"Install"
"Configure"
"Run"
);
}
This can make a technical checklist easier to scan when the marker itself communicates the step.
Why Use symbols()?
Without custom counter styles, developers often use additional HTML or pseudo-elements.
For example:
.step::before {
content: "Step";
}
That approach can work, but it mixes the visual marker with the content structure.
With a counter style:
.setup {
list-style-type: symbols("Create" "Install" "Configure" "Run");
}
the list semantics remain intact.
This is particularly useful when the content is genuinely a list and the custom marker is presentation.
symbols() With Repeating Values
A custom symbol sequence can also be used for repeated counters.
For example:
.list {
list-style-type: symbols("A" "B");
}
For a longer list, the counter style can continue according to the defined symbol system rather than requiring developers to manually add labels to every item.
This is one reason CSS counter styles are useful for generated numbering.
Using Symbols With Ordered Lists
You can apply the style to an ordered list:
ol.steps {
list-style-type: symbols("Step 1" "Step 2" "Step 3");
}
HTML remains straightforward:
<ol class="steps">
<li>Prepare the environment</li>
<li>Build the application</li>
<li>Deploy the application</li>
</ol>
This keeps the order represented by HTML rather than hard-coding numbers into the markup.
symbols() vs ::before
These approaches solve different problems.

Join the conversation! Your thoughts help the community grow.