🔢 CSS counter() — Complete Tutorial
🌐 What Is counter() in CSS?
The counter() function is used to display the value of a CSS counter inside the content property. It works with counter-reset and counter-increment to create fully automatic numbering systems in pure CSS.
>>“counter() turns CSS counters into visible text — perfect for numbering headings, lists, steps, and more.”
Note
✔ Must be used inside content
✔ Works only in pseudo-elements (::before, ::after)
✔ Can style output using built-in formats (e.g., roman, alpha)
✔ Works only in pseudo-elements (::before, ::after)
✔ Can style output using built-in formats (e.g., roman, alpha)
📦 Syntax
counter() Syntax
content: counter(counterName, optionalStyle);| Parameter | Description |
|---|---|
| counterName | Name defined in counter-reset |
| optionalStyle | Numbering style (roman, alpha, etc.) |
📌 Example 1 — Basic Counter Output
Basic example
body {
counter-reset: section;
}
h2::before {
counter-increment: section;
content: counter(section) ". ";
}Produces: 1. Heading, 2. Heading, 3. Heading…
📌 Example 2 — Roman Numerals
Roman numbering
h2::before {
counter-increment: sec;
content: counter(sec, upper-roman) ". ";
}Output: I, II, III, IV…
📌 Example 3 — Alphabetic Counters
Alphabetical numbering
li::before {
counter-increment: item;
content: counter(item, lower-alpha) ") ";
}Output: a) b) c) d) …
📌 Example 4 — Combining Counters (1.1, 1.2, 2.1…)
Nested numbering
body {
counter-reset: section;
}
h1 {
counter-reset: subsection;
counter-increment: section;
}
h1::before {
content: counter(section) ". ";
}
h2 {
counter-increment: subsection;
}
h2::before {
content: counter(section) "." counter(subsection) " ";
}Produces hierarchical numbering like 1.1, 1.2, 2.1
📌 Example 5 — Styled Counter Output
Styled counter
.step::before {
counter-increment: step;
content: "Step " counter(step);
font-weight: bold;
color: #333;
}📌 Example 6 — Using Multiple Counters in One Content Value
Multiple counters
.task::before {
counter-increment: major minor;
content: counter(major) "." counter(minor) " → ";
}📌 Example 7 — Prefix & Suffix Content
Prefixed content
.question::before {
counter-increment: q;
content: "Q" counter(q) ": ";
}📌 Example 8 — Dynamic List Numbering
List example
ol {
list-style: none;
counter-reset: li;
}
li::before {
counter-increment: li;
content: counter(li) ") ";
}🎨 Styling the Counter Badge
Badge styling
.badge::before {
counter-increment: badge;
content: counter(badge);
background: red;
color: white;
padding: 4px 8px;
border-radius: 50%;
margin-right: 8px;
}🧠 Supported Counter Styles
| Style | Output Example |
|---|---|
| decimal | 1, 2, 3 |
| lower-alpha | a, b, c |
| upper-alpha | A, B, C |
| lower-roman | i, ii, iii |
| upper-roman | I, II, III |
| cjk-decimal | 〇, 一, 二… |
Note
Modern CSS also supports custom counter styles via @counter-style.
🧪 Real-World Examples
1️⃣ Table of Contents
TOC numbering
.toc {
counter-reset: toc;
}
.toc-item::before {
counter-increment: toc;
content: counter(toc) ". ";
}2️⃣ Numbered Chat Messages
Chat numbering
.chat {
counter-reset: msg;
}
.message::before {
counter-increment: msg;
content: "#" counter(msg) ": ";
}3️⃣ Auto-numbered Cards in a Grid
Grid numbering
.grid {
counter-reset: card;
}
.card::before {
counter-increment: card;
content: counter(card);
}⚠️ Common Mistakes
- ❌ Forgetting to declare counter-reset
- ❌ Using counter() outside content
- ❌ Not incrementing the counter → stays at 0
- ❌ Expecting counters to work without pseudo-elements
Note
✔ Always combine counter-reset, counter-increment, and counter().
✔ Use @counter-style for custom numbering systems.
✔ Use @counter-style for custom numbering systems.
🔥 Summary
The counter() function displays CSS counter values and makes automatic numbering possible. Whether you're numbering sections, creating step indicators, or building structured interfaces, counters are a clean, flexible, and pure-CSS solution.
>>“CSS counters replace manual numbering — clean, dynamic, and effortless.”
Learn more →MDN Docs 📘