DEV Community

Cover image for You don't need... JavaScript to do tabs

Posted on

You don't need... JavaScript to do tabs


The current development ecosystems we code in make it so easy to make a highly interactive experience with client-side code. Sometimes we reach for JavaScript (or worse yet, a whole framework) when we should hold off on that for as long as possible.

This is the first of (hopefully) many entries in a series I like to call You don't need...

What do we need for tab navigation?

To do tabs we need to do 2 things:

  1. Track the current tab index
  2. Show and hide tab content based on the index

And CSS can do both!

The principals

CSS has a class of selectors called a sibling selector (+ for immediately after and ~ for somewhere after) which will select a sibling element (one that is on the same "level" and shares their containing element).

CSS also has nth pseudo selectors, specifically the :nth-of-type(i) selector which will select the ith element of whatever selector you put before it.

The CSS principal you need to understand is the :checked pseudo selector which applies to input elements that have been checked (like a radio button or check box

Getting it done

Track the current tab index

In JavaScript we would update the tab index whenever we clicked on the tab. CSS has a way of tracking input element state with :checked as mentioned above so we can detect this in CSS with where i is the index of the tab selected. We can make a new rule for every tab but it's kind of useless without some action based on the index

Show and hide tab content based on selected index

For starters, the default state of a tab is hidden so I think display: none on our tab content is obvious. And showing it is as simple as display: block. The trick is showing the ith content when the ith tab is selected. For that we use the ~ (general sibling) selector. As long as your tabs are of one type (probably a label element for each of your hidden input state-managing elements) and your content is another type (a div maybe?) then you can group them as different "types" and use a rule like to select the first tab content element whenever the first tab is selected

A working example

JSFiddle link

You can also change the input type to checkbox for toggles JSFiddle link

How long does it take for you to resort to JavaScript to perform interactivity on an otherwise static site?

I am curious what other people think of avoiding JavaScript. I personally prefer to avoid it if the site is going to be mostly static since it means all my noscript users still have a good experience. At the very least, I want them to be able to sucessfuly use the site in a limited form, even if the optional frills I throw in do not function

Discussion (3)

jamesthomson profile image
James Thomson • Edited on

Or you could just use CSS's :target selector. Not only is this a simpler implementation, but it also supports "deep linking" via the hashed url value.


Edit: Downside is there doesn't seem to be a way to apply an active state to the tab. So with either approach we can only meet 2/3 of the requirements to make usable tabs. So, once again, this is why we end up turning to JS.

jonosellier profile image
jonosellier Author

I like using :target for routing (spoilers for the next article! 🤫) but I also don't have a good way of doing active states nicely.

I was thinking of showing it being done with a bunch of copies of tabs where 1 is manually marked as active with a class so the Tab and Tab Content is swapped based on active state. I decided not to because it's a lot of repetition.

palalet profile image

Im doing websites for ages, i mean, 20+ years. And i've never met anyone, who has scripts disabled. I understand the idea, but this should not be the motivation. I am sure there are some users who do not allow script to run, but motivation should be size of the page, speed on low end devices, something you can measure and verify, if time spent on such solution was worth it or not.