Tabs control example using css only, no js

I recently made a minimalist tabs control using nested shortcodes.

CSS only, no javascript. This works by using a radio input with some CSS 3 sibling selector goodness. No CSS frameworks necessary either, but if you did want to use a framework just use your own CSS - hopefully the tabs->tab nesting of the shortcode is still useful as a template.

You can see an example of this in action here: run your first pipeline | pypyr

Since I usually check this excellent forum for implementation examples & suggestions 1st, I thought I’d share this here and maybe it’s of use to someone. . .

  1. The outer tabs control.
    layouts/shortcodes/tabs.html
<div class="tabs">
    {{ .Inner }}
</div>
  1. The inner tab
    layouts/shortcodes/tab.html
{{ $tabName := .Get "name" }}

{{ $tabsId := .Parent.Get "id" }}

{{ $id := printf "%s-radio-%s" $tabsId $tabName }}

<input type="radio" id="{{ $id }}" name="{{ $tabsId }}-selector" class="tab-radio" tabindex="0"{{ if eq .Ordinal 0 }} checked {{ end }}>

<label for="{{ $id }}" class="tab-label">{{ $tabName }}</label>

<div class="tab">

{{ .Inner | markdownify }}

</div>
  1. The css
    (You’ll have to replace the var() assignments with your own values as you see fit for colors/spacing etc.)
/* ******************* tabs ******************************************* */
.tabs {
  display: flex;
  flex-wrap: wrap;
  margin: var(--gap) 0;
}

.tab-radio {
  position: absolute;
  opacity: 0;
}

.tab-label {
  color: var(--text-on-surface-disabled);
  cursor: pointer;
  font-size: 0.95rem;
  font-weight: 600;
  padding: 4px 24px;
  transition: background 0.3s, color 0.3s;
  text-align: center;
}

.tab-label:hover {
  background: var(--background-elevation-01);
}

.tab-label:active {
  background: var(--secondary);
}

.tab-radio:checked + .tab-label {
  border-bottom: solid 2px var(--primary-dark-variant);
  color: var(--primary-dark-variant);
  cursor: default;
}

.tab {
  display: none;
  background: var(--background-elevation-01);
  order: 1;
  width: 100%;
}

.tab-radio:checked + .tab-label + .tab {
  display: block;
}

/* ******************* END tabs ******************************************* */
  1. Example in use in your content .md files:
{{< tabs id="this-id-must-be-unique-per-page" >}}
{{< tab name="tab1" >}}
```yaml
hello: tab 1
```
{{< /tab >}}
{{< tab name="tab2" >}}
```toml
hello = "tab 2"
```
{{< /tab >}}
{{< /tabs >}}

The Tabs id uniquely identifies the control on the page.
The name on each nested tab is the caption on top of the tab that you click to activate it.

2 Likes