A CSS Only Tabs Prototype (No JavaScript Required)

July 2026

Component Kickoff

I was listening to an episode of Shop Talk Show that discussed putting native HTML elements inside web components instead of having the component insert them. For example, a fancy-checkbox component could contain a checkbox element:

<fancy-checkbox>
  <label for="checkbox-x">Show Example</label>
  <input id="checkbox-x" type="checkbox" />
</fancy-checkbox>

Or, it could be empty, pushing the responsibility for adding the checkbox element into the component itself.

<fancy-checkbox></fancy-checkbox>
With the first one, a checkbox shows up even if JavaScript or the web component fails to load. Not so with the second.

Modal Pondering

The conversation got me wondering what you can do with a checkbox if there's no JavaScript running on the page. Specifically, I was wondering if you could do something like make a dark mode switcher using only HTML and CSS. The answer is, yes, you can.

Check this out:

There's no JavaScript involved. Everything happens thanks to this HTML:

<div class="mode-wrapper-x">
  <label for="mode-checkbox-x">
    Activate Dark Mode:
  </label>
  <input id="mode-checkbox-x" type="checkbox" />
</div>

and this CSS:

:root {
  --mode-wrapper-background-x: white;
  --mode-wrapper-color-x: black;
}

.mode-wrapper-x {
  background-color: var(--mode-wrapper-background-x);
  color: var(--mode-wrapper-color-x);
}

body:has(#mode-checkbox-x:checked) {
  --mode-wrapper-background-x: black;
  --mode-wrapper-color-x: white;
}

The magic is the :has() pseudo-class on the body element on line 11. It watches the #mode-checkbox-x element to see if it's check. When it is, it overrides the default property variables to do the switch.

Tab Coded

Of course, the dark mode switcher doesn't set anything on the browser to maintain the mode between pages. You would need JavaScript for that.

However, there are other things that don't require keeping track of state across pages. Tabs come to mind. For example:

Content 1
Content 2
Content 3

Again, no JavaScript. Just this HTML:

<div>
  <input id="tab1" type="radio" name="tabSwtich" checked />
  <label for="tab1" >Tab 1</label>

  <input id="tab2" type="radio" name="tabSwtich" />
  <label for="tab2">Tab 2</label>

  <input id="tab3" type="radio" name="tabSwtich" />
  <label for="tab3">Tab 3</label>
</div>

<div id="content1">Content 1</div>
<div id="content2">Content 2</div>
<div id="content3">Content 3</div>

and this CSS:

body:has(#tab1:checked){ 
  --content-1-display-x: block; 
  --content-2-display-x: none; 
  --content-3-display-x: none; 
}

body:has(#tab2:checked){ 
  --content-1-display-x: none; 
  --content-2-display-x: block; 
  --content-3-display-x: none; 
}

body:has(#tab3:checked){ 
  --content-1-display-x: none; 
  --content-2-display-x: none; 
  --content-3-display-x: block; 
}


#content1 {
  display: var(--content-1-display-x);
}

#content2 {
  display: var(--content-2-display-x);
}

#content3 {
  display: var(--content-3-display-x);
}

First Try

To be clear: this is a prototype. It's purpose is a first test to see what's possible. There's several things to investigate, including:

Overall, it's very exciting. Even if there are reasons not to do it now, the continuing march of CSS makes me think it won't be long.

-a

References

  • The CSS :has() pseudo-class which provides the horsepower for the functionality. It hit Baseline Widely Available in December 2023.

Endnotes

  • Thanks to Alex for introducing me to :has() and showing me how to use it.

  • If you've got feedback on the accessibility aspects of this approach please hit me up on Bluesky or Mastodon

  • Another thing I learned about is command and commandfor for buttons. Feels like there's a lot of potential there in future updates.

  • Another episode of Shop Talk Show was an interview with Dan Abramov about AT Proto. I'd been toying with the idea of creating a lexicon for Neopolitan (my markdown replacement format). After the episode, I'm absolutely gonna do it. The goal being to provide a nice way to created pages and posts using less than HTML but more than Markdown.

    One of the biggest considerations is if JavaScript will be allowed. I love the idea of providing for interaction. I hate the idea of introducing the security issues that come with the language. Seeing this prototype seals the deal. Current CSS can do so much the reward of introducing the JavaScript risk isn't worth it. And, I expect CSS will get nothing but more powerful.

id = "01/n6/a8/6j"