Intro
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:
- Track the current tab index
- 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 i
th 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 input.tab:checked:nth-of-type(i)
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 i
th content when the i
th 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 input.tab:checked:nth-of-type(1)~div.tab-content:nth-of-type(1)
to select the first tab content element whenever the first tab is selected
A working example
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
Top comments (3)
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.Example: stackblitz.com/edit/web-platform-2...
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.
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.
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.