🔢 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)

📦 Syntax

counter() Syntax

content: counter(counterName, optionalStyle);
ParameterDescription
counterNameName defined in counter-reset
optionalStyleNumbering 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

StyleOutput Example
decimal1, 2, 3
lower-alphaa, b, c
upper-alphaA, B, C
lower-romani, ii, iii
upper-romanI, 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.

🔥 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 📘