v135 · css

Timeline list

A step-by-step timeline using ::before::marker — the nested pseudo introduced in Chrome 135. The ::before generates a visual bullet (step number, status badge, or emoji), and ::before::marker suppresses the default list bullet so it doesn't double up. Pure CSS, no wrapper elements required.

::before::marker: checking…
Before: manual workarounds
list-style: none on the parent to kill the marker, then use ::before to fake a bullet. You lose semantic list structure or have to add wrapper elements to restore it.
After: ::before::marker
Keep list-style-type: disc for accessibility. Style the ::before as a custom counter/badge. Use ::before::marker { content: "" } to suppress just the default marker on that pseudo, not the whole list.
List style
Chrome 135 feature timeline
  1. Proposal & explainer TC39 / WICG stage — initial proposal written
  2. Spec drafted CSS Working Group draft published
  3. Chromium implementation Feature flag added to Chrome DevChannel
  4. Origin trial Developer testing — Chrome 134 origin trial
  5. Shipped in Chrome 135 Stable, unflagged, available to all users
  6. Other browsers Firefox & Safari — under consideration
Toggle step:
/* ::before generates the custom bullet, ::before::marker suppresses the default */
.timeline {
  list-style: none;
  padding-left: 2rem;
  counter-reset: step;
}

.timeline li {
  counter-increment: step;
  list-style-type: disc; /* keep disc for AT — ::before::marker will hide it visually */
}

.timeline li::before {
  content: counter(step);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.5rem;
  height: 1.5rem;
  background: black;
  color: white;
  font-size: 0.65rem;
  font-weight: 700;
  margin-right: 0.6rem;
}

/* Chrome 135: nested pseudo suppresses the default bullet on ::before only */
.timeline li::before::marker {
  content: ""; /* hides the disc that ::before would otherwise also emit */
}

see also

references