1 Thing A Week 1 Thing
A Week

Revisiting how to build a CSS only slideshow

Week 274.0 — 23rd January '23

Almost 3 years ago, I put together some CSS demos on CodePen. The one I was most proud of was a pure-CSS and HTML slideshow. The demo is fairly crude and it had three key issues:

  • I couldn't figure out how to highlight the current slide in the pagination
  • It relied on the <a> tag which the page to jump when going through the slideshow
  • I couldn't automatically cycle through images

Happy to say though, after an interaction on Twitter where I shared my post but the page jumps were pointed out. Given it had been 3 years and CSS has moved on I decided to attempt a slight re-write to achieve what I set out to achieve.

And here is my second version of a CSS only slideshow:

The only thing to note is that it still doesn't automatically go through the slides and I think that would most likely be achieved with JavaScript. In this case it would be progressive enhancement so I'd be willing to concede that point. Otherwise, this genuinely is a pure-CSS slideshow!

How to build a CSS only slideshow

I wanted to evolve what I'd built before, which was based on the <a> tag and the :target attribute, now it uses radio buttons and the :has() selector.

It took me a while to realise I could place labels elsewhere, so all aspects of the pagination are now driven by labels.

Putting the pagination aside, each slide has a next and previous input and label. If you select an input (hidden) by clicking on the label (visible), then the :has() selector is used to find the checked input from deep inside the slideshow and then allow the slide that's been requested to come to the forefront.

Using these same selectors, I can now also highlight the pagination which wasn't possible before and these have also become labels which just point to specific radio inputs.

Why not to build a CSS only slideshow

The one thing that is a bit of a pain is the fact that I've had to specify the CSS combinations for each slide. This means I couldn't have a dynamic number of slides... rather than setting specific IDs, maybe it would be possible with the :nth-child() and :has() selectors but it feels like it would just be another layer of complication rather than a robust solution.

In the real world, I'd probably programatically figure it out with a @for loop, but that's beyond the scope of a proof of concept.

Would I use a CSS only slideshow in production?

I definitely would, I'd have to refactor it but it's certainly possible and would mean I avoid JavaScript yet again!


After some more feedback, I've taken another fork and now added a check that :has() is supported by the browser. If not, then the pagination is hidden and only the first slide is show. I updated the embedded pen above to show v3, but if you want, you can still check out v2 on CodePen.

More from 1 Thing A Week
« Is Twitter getting better? Two things Apple need to fix in Spaces for macOS Why are all-in-one remotes so bad? »



Quick links and commentary on interesting articles, videos and more throughout the week.

  1. 274.3 – Wednesday
    1. Study Suggests That Hardware Buttons in Cars Are Safer and Quicker to Use Than Touchscreens daringfireball.net

Jump to notable items for Week #273, Week #275 , view the notable archive or my favourites.

About 1 Thing A Week

A website curated by @cchana bringing you 1 Thing A Week, delivered every Monday morning.

You can find a list of all articles in the archive, or read the most popular.

Find out more about 1 Thing A Week or read the privacy policy.


Visit the market and support 1 Thing A Week.

You can find 1 Thing A Week on Twitter, Facebook, Instagram & Reddit