# CSS only counter component

DevFeed: [CSS only counter component](<https://devfeed.tech/articles/css-only-counter-component-37256.md>)

Original publisher: [Read original article](<https://muffinman.io/blog/css-only-counter/>)

Author: Stanko

Published: 2025-08-05T00:00:00Z

Content type: tutorial

Language: en

Sources: [Stanko Tadić](<https://devfeed.tech/sources/stanko-tadic.md>)

Topics: [CSS](<https://devfeed.tech/topics/css.md>), [HTML](<https://devfeed.tech/topics/html.md>), [Code](<https://devfeed.tech/topics/code.md>), [Web Development](<https://devfeed.tech/topics/web-development.md>)

Tags: [code](<https://devfeed.tech/tags/code.md>), [css](<https://devfeed.tech/tags/css.md>), [html](<https://devfeed.tech/tags/html.md>), [interactive](<https://devfeed.tech/tags/interactive.md>)

## AI overview

A tutorial explaining how to build a counter component using only CSS. It uses pre-rendered HTML radio inputs, labels, and the :has selector to show the checked, previous, and next values, with additional sections on buttons, looping, and hover behavior.

## Source excerpt

Before we start, here is a demo of the counter (you can also check it out on CodePen): 12345678910 - + This idea started with a space invaders generator I recently made. If you look at the randomize button, you'll notice the number on the dice changes from five to three when you hover over it. A friend then said, "It would be really cool if you showed a different number every time you hover." That got me thinking, could I make this using CSS only?It's trivial to do in a few lines of JavaScript, which I'll probably do at some point. Before diving deeper, I decided to simplify the problem by first making a basic counter component. Since the solution had to be CSS-only, we'd need to render all the numbers before hand and then select one at a time using CSS - which felt a lot like how radio inputs work. So I decided to try radio inputs. After a bit of experimenting, I ended up with this HTML structure: <div class="counter"> <input id="counter-1" type="radio" value="1" name="counter" checked /> <label for="counter-1">1</label> <input id="counter-2" type="radio" value="2" name="counter" /> <label for="counter-2">2</label> <!-- ... --> <input id="counter-10" type="radio" value="10" name="counter" /> <label for="counter-10">10</label> </div> Solution # To make a counter, we need to somehow select the checked input's label, as well as the previous and next ones, using CSS. Lucky for us, we live in the future where the :has selector exists. If you had shown me :has back when we were still dealing with IE6, it would have completely blown my mind. Anyway, we can use this fancy selector to target the inputs we need, and it's fairly simple: /* Checked label */ input:checked + label {} /* Prev label */ label:has(+ input:checked) {} /* Next Label */ input:checked + label + input + label {} I hope this code is clear as it is, but to make things easier to grasp here is an interactive demo: 123456 This demo uses the exact code we have above (plus a ::before element for labels) to high