CSS power-up: count code lines in pure CSS

gabcimato profile image Gabriele Cimato ・Updated on ・3 min read

I decided to start a series called CSS power-up! I will be collecting small posts about neat CSS features. There's one specifically that I was very impressed by. Not only for how intuitive it is but also for its widespread browser support.

Tired of having overly priced note-taking apps, or free ones that don't offer what I need, I decided to create my own! That's why I started a side project that led to rediscovering an interesting CSS property.

It all started with Slate.js, which provides a library to build rich text editors. One feature I was looking for in my app, was the ability to add code blocks. I soon found a plugin called slate-code that does it for me. How convenient! After fiddling with it a bit here's the result:

Code block

Now this looks fine but, I'm sure you noticed something is missing. Where is the line count ? Armed with patience I decided to go down the rabbit hole, convinced it would be a painful journey. At first I thought about using some sort of index reference to each line and display that on the side. But handling deleting and insertion of lines seemed overly complicated πŸ€”.

Then I remembered that you could do that very intuitively with CSS only! I was thrilled πŸ˜€! The way it works is by creating a named counter and specifying which CSS class increments that counter. On top of that you also have access to the counter value that you can display as content.

Let's dig into it. First let's define the class of the container of the code block.

.code {
    background: #f7f9fa;
    border: 1px solid #e6e8eb;
    font-family: "Lucida Console",Monaco,monospace;
    overflow: auto;
    padding: 8px;
    white-space: pre;
    counter-reset: line;

With counter-reset: line we are defining and initializing a counter named line with the value 0.

Now we need to determine which class will be in charge of incrementing the counter. We use the counter-increment property for that and give it the value of the counter name we want to increment, in our case line.

To finish up we also want to display the counter value. Using counter(line) with the content property that's exactly what we get. As an extra you can add the -webkit-user-select: none to prevent user from selecting the counter values. This is helpful when you want to copy a whole code block.

.code-line::before {
    counter-increment: line;
    content: counter(line);
    -webkit-user-select: none;
    font-size: 10px;
    color: grey;
    margin-right: 10px;
    text-align: right;
    display: inline-block;
    width: 18px;

And the result is the following:

Code block

The rest of the styling is pretty arbitrary and up to you. As you can see it was quite easy to add something as simple as a line count. You can find the full reference here. At first I was very thrilled by the simplicity of this method then I remembered that I had to check browser support.

CSS Counters Support is over 95%

πŸŽ‰ What a victory! We went from panicking about ways to implement a line counter to having a simple CSS property that is widely supported. I hope you found this as interesting as I did. Is there any not-so-popular CSS property that left you "wowed" ? Have you used the line counter before ?

If you want to see a live demo, you can find one here.

πŸ‘‹ Hi, I’m Gabri! I love innovation and lead R&D at Hutch. I also love React, Javascript and Machine Learning (among a million other things). You can follow me on twitter @gabcimato and on GitHub @Gabri3l. Leave a comment or send a DM on Twitter if you have any questions!


Editor guide