How to enable two radioboxes when clicking one label?

Viewed 71

I want to implement a page control which does not use javascript. The idea is to use the input:checked + <element> selector. Showing only the selected page is no problem, but it seems not to be possible to have both: active tab and page.

May be it is possible to activate two radiobuttons at once with a label without using javascript?

input {
  position: absolute;
  width: 0;
  height: 0;
}

.tabs {
  display: flex;
}

.tabs > label,
.pages {
  padding: 10px;
  background-color: #eee;
  border: 1px solid #ddd;
}

.tabs > input:checked + label {
  background-color: green;
}

.tabs > label {
  border-bottom: none;
  border-right-width: 0;
}

.tabs > label:last-child {
  border-right-width: 1px;
}

.pages > div {
  display: none;
}

.pages > input:checked + div {
  display: block;
}
<div class="tabs">
 <input type="radio" name="tab" id="tab1" checked="checked">
 <label for="page1">First Tab</label>
 <input type="radio" name="tab" id="tab2">
 <label for="page2">Second Tab</label>
 <input type="radio" name="tab" id="tab3">
 <label for="page3">Third Tab</label>
</div>
<div class="pages">
 <input type="radio" name="page" id="page1" checked="checked">
 <div>Page Content #1</div>
 <input type="radio" name="page" id="page2">
 <div>Page Content #2</div>
 <input type="radio" name="page" id="page3">
 <div>Page Content #3</div>
</div>

The page control itself is working here. But I want to highlight the active tab. Please note: I don't want to use js (it's easy with js). I don't want to use any lib. The html and css structure can be changed in any way to reach the goal.

2 Answers

New solution

I have arranged a new solution which allows to preserve most of your original html structure so you can still use the flex layout, without the need to duplicate the tabs code for each page as in your last update. The main difference is that I've moved the radio inputs in a parent container, so the css rules can match both tabs and pages. You still have to code N css rules, where N must be greater than the maximum number of tabs allowed:

input {
  position: absolute;
  width: 0;
  height: 0;
}

.tabs {
  display: flex;
}

.tabs > label, .pages {
  padding: 10px;
  background-color: #eee;
  border: 1px solid #ddd;
}

.tabs > label {
  border-bottom: none;
  border-right-width: 0;
}

.tabs > label:last-child {
  border-right-width: 1px;
}

.pages > div {
  display: none;
}

.TabPane>input:checked:nth-child(1)~.tabs>label:nth-child(1) {background-color: green;}
.TabPane>input:checked:nth-child(1)~.pages>div:nth-child(1) {display: block;}

.TabPane>input:checked:nth-child(2)~.tabs>label:nth-child(2) {background-color: green;}
.TabPane>input:checked:nth-child(2)~.pages>div:nth-child(2) {display: block;}

.TabPane>input:checked:nth-child(3)~.tabs>label:nth-child(3) {background-color: green;}
.TabPane>input:checked:nth-child(3)~.pages>div:nth-child(3) {display: block;}
<div class="TabPane">
            <input type="radio" name="tab" id="tab1" checked="checked">
            <input type="radio" name="tab" id="tab2">
            <input type="radio" name="tab" id="tab3">
            <div class="tabs">
                <label for="tab1">First Tab</label>
                <label for="tab2">Second Tab</label>
                <label for="tab3">Third Tab</label>
            </div>
            <div class="pages">
                <div>Page Content #1</div>
                <div>Page Content #2</div>
                <div>Page Content #3</div>
            </div>
        </div>

Old solution

The problem with css selectors is that they allow to select only children and sibling elements; since your tabs and pages belong to different containers then there is no way to connect them using pure css selectors. A solution could be to reorganize the html structure to have both elements within the same container. The following code works as long you define enough rules to handle up to n tabs:

input {
    position: absolute;
    width: 0;
    height: 0;
}

.tabs > label, .tabs > div {
    padding: 10px;
    background-color: #eee;
    border: 1px solid #ddd;
}

.tabs > input:checked + label {
    background-color: green;
}

.tabs > label {
    border-bottom: none;
    border-right-width: 0;
}

.tabs > label:last-of-type {
    border-right-width: 1px;
}

.tabs > div {
    display: none;
}

.tabs > input#tab1:checked ~ div#page1 {display: block;}
.tabs > input#tab2:checked ~ div#page2 {display: block;}
.tabs > input#tab3:checked ~ div#page3 {display: block;}
<div class="tabs">
            <input type="radio" name="tab" id="tab1" checked="checked">
            <label for="tab1">First Tab</label>
            <input type="radio" name="tab" id="tab2">
            <label for="tab2">Second Tab</label>
            <input type="radio" name="tab" id="tab3">
            <label for="tab3">Third Tab</label>
            <div id="page1">Page Content #1</div>
            <div id="page2">Page Content #2</div>
            <div id="page3">Page Content #3</div>
    </div>

Inspired by @Daniels118 solution I've found it. Because label:radiobutton relation is not possible as 1:n, I inverted the relation. So n-labels are pointing to 1 specific radio button.

I repeat all tabs for each page. There is only one difference: The active tab has an active class.

With the input:checked + .tabs and input:checked + .tabs + .page selector only the current tab is visible.

This solution is easier to layout on mobile devices. It's also extendable without changing the css. My widget class will output the tabs automatically for each page.

Because there is only one radio button that is focused by the label the focus just works fine (when having for example input controls in a page).

.tabs,
.page {
  display: none;
}

.pages > input {
  position: absolute;
  width: 0;
  height: 0;
}

.tabs > label,
.page {
  padding: 10px;
  background-color: #eee;
  border: 1px solid #ddd;
}

.tabs > label {
  border-bottom: none;
  border-right-width: 0;
  user-select: none;
}

.tabs > label:last-child {
  border-right-width: 1px;
}

.tabs > label.active {
  background-color: green;
}

.pages > input:checked + .tabs {
  display: flex;
}

.pages > input:checked + .tabs + .page {
  display: block;
}

.pages > input:focus + .tabs > .active {
  text-decoration: underline;
}
<div class="pages">
 <input type="radio" name="page" id="page1" checked="checked">
 <div class="tabs">
  <label for="page1" class="active">First Tab</label>
  <label for="page2">Second Tab</label>
  <label for="page3">Third Tab</label>
 </div>
 <div class="page">Page Content #1</div>
 <input type="radio" name="page" id="page2">
 <div class="tabs">
  <label for="page1">First Tab</label>
  <label for="page2" class="active">Second Tab</label>
  <label for="page3">Third Tab</label>
 </div>
 <div class="page">Page Content #2</div>
 <input type="radio" name="page" id="page3">
 <div class="tabs">
  <label for="page1">First Tab</label>
  <label for="page2">Second Tab</label>
  <label for="page3" class="active">Third Tab</label>
 </div>
 <div class="page">Page Content #3<br /><input type="text" placeholder="To test the focus" /></div>
</div>

Related