CSS @counter-style Reference

Built-in CSS counter styles and @counter-style descriptor syntax.

Reference for CSS list counter styles including decimal, roman, alphabetic, greek and symbolic markers, plus the @counter-style descriptors system, symbols, range, pad and fallback, with a live number renderer. It runs free in your browser on Gera Tools, with nothing uploaded.

Last updated Source: Gera Tools

How do I use a counter style?

Set list-style-type to the style name on an ol or ul, for example list-style-type: upper-roman. You can also reference a style inside generated content with the counter() function, such as content: counter(item, lower-alpha). Custom styles defined via @counter-style work in both places.

Numbering and bullets, your way

CSS list markers are not limited to 1. and . A large set of predefined counter styles cover numeric, alphabetic, Roman, Greek, CJK and symbolic numbering, and the @counter-style at-rule lets you invent your own. This reference lists the common built-ins, the rule’s descriptors, and renders a number into several styles live.

How it works

A counter style maps an integer to a marker string. The built-ins fall into families: numeric (positional, like decimal), alphabetic (bijective base-N letters), additive (weighted symbols summed together, like Roman numerals and Hebrew), and symbolic (a fixed glyph such as disc). The live demo above implements the real algorithms: bijective base-26 for lower-alpha, subtractive Roman assembly for upper-roman, and zero-padding for decimal-leading-zero.

To define a custom style, write @counter-style name { system: …; symbols: …; }. The system chooses the algorithm, symbols or additive-symbols supply the glyphs, and range, pad, negative, prefix, suffix and fallback refine the output. Outside the declared range, or for unrepresentable values, the fallback style (default decimal) takes over.

Custom counter styles in practice

Zero-padded step numbers — for a tutorial with steps 01, 02 … 09, 10:

@counter-style padded-decimal {
  system: extends decimal;
  pad: 2 "0";
}
ol { list-style-type: padded-decimal; }

The extends decimal system reuses the standard numeric algorithm but applies pad: 2 "0" to ensure at least two characters, so 1 becomes 01.

Emoji bullets — purely decorative markers using cyclic repetition:

@counter-style stars {
  system: cyclic;
  symbols: "★" "☆";
  suffix: " ";
}
ul.fancy { list-style-type: stars; }

cyclic repeats through the symbols list, so items alternate between filled and outlined stars. The suffix replaces the default ". " for numeric styles.

Roman numeral appendix with a decimal fallback:

@counter-style appendix {
  system: additive;
  additive-symbols: 1000 "M", 900 "CM", 500 "D", 400 "CD",
                     100 "C",  90 "XC",  50 "L",  40 "XL",
                      10 "X",   9 "IX",   5 "V",   4 "IV",
                       1 "I";
  range: 1 3999;
  fallback: decimal;
}
ol.appendix { list-style-type: appendix; }

The range: 1 3999 matches the practical range for Roman numerals; items outside it fall back to plain decimal.

Tips and examples

  • Apply a style with list-style-type, or reuse it anywhere via the counter() and counters() functions in content.
  • Always set a sensible range and fallback for additive styles so zero and large numbers stay legible.
  • system: extends decimal is the easy way to tweak only the prefix or suffix of an existing style without re-listing every symbol.
  • Predefined symbolic markers (disc, circle, square) ignore the counter value — they repeat the same glyph for every item.
  • The negative descriptor controls what is prepended and appended for negative counter values; its default is a minus sign prepended, but you can change both parts.