Toggle Elements without Javascript
December 2021
Introduction
I’ve been spending my time building a forum where the frontend is only HTML and CSS. The inspiration is from the recent trend of projects hosting their discussions on Discord, which is great for real-time, short discussions, but not for ones with details and worth indexing for future searches. And Javascript frameworks are taking over the web, I thought it would be a nice challenge to build something without Javascript, and forums shouldn’t need fancy Javascript to work.
Along the way, I wanted to make a “Reply” button that would toggle a reply form to a discussion. I can make it a link to a separate page, but that would disrupt users as it takes the discussion away from them.
After searching the internet for a bit, I found that this is possible using only CSS, so I want to write this down as I thought it was pretty cool. Please note this is not my idea, I just want to share this finding.
CSS Selectors
Since I started programming, I’ve only needed to use some simple selectors like sibling (~
), child (>
), hover (:hover
), etc. But they are so much more powerful than that.
One particularly useful selector is :checked
, which selects checked input elements. This allows us to use checkboxes as the state storage to toggle an element.
<style>
#state:checked ~ #content {
display: inline-block;
}
#state:not(checked) ~ #content {
display: none;
}
</style>
<input id="state" type="checkbox" />
<span id="content">
Hello there!
</span>
Which would result in this:
Now that checkbox doesn’t really pass as a button. But we can use a <label>
for that instead. And, to my surprise, an invisible checkbox can still be checked. So our code would turn into
<style>
#state {
display: none;
}
#state:checked ~ #content {
display: inline-block;
}
#state:not(checked) ~ #content {
display: none;
}
</style>
<input id="state" type="checkbox" />
<label id="button" for="state">Click me!</labe>
<span id="content">
Hello there!
</span>
And here is the code in action:
That’s it!