0

I am creating a custom checkbox and want clicking the label text to also toggle the state and show or not show a text depending of the state of the checkbox just using CSS. I wrote this html:

input[type="checkbox"] {
    display: none;
}

input[type="checkbox"] + .label-text:before{
    content: "+";
    width: 1em;
    height: 1em;
    display: inline-block;
    margin-right: 5px;
}

input[type="checkbox"]:checked + .label-text:before{
    content: "-"; 
}

label input[type="checkbox"]:checked ~ .elements .is_not_checked{
    display: none;
}

label input[type="checkbox"]:not(:checked) ~ .elements .is_checked{
    display: none;
}
<label>
    <input type="checkbox" name="check"> <span class="label-text">Item Two</span>
    <div class="elements">
      <div class="is_checked">
          Checkbox is checked
      </div>
      <div class="is_not_checked">
          Checkbox is not checked
      </div>
</label>

This works. But I am not happy with the checkbox changing state when I click on the element text. However, when I move the elements out of the label I can no longer access the checkbox state. I tried:

(label > input[type="checkbox"]:checked) ~ .elements .is_not_checked{
    display: none;
}

But this did not even hide the text. How can I access the state of a checkbox hidden in another element (label in this case) just using CSS?

mrCarnivore
  • 4,638
  • 2
  • 12
  • 29
  • No...it wouldn't the element is not a sibling of the input any more so **you can't refer to it in CSS** – Paulie_D Sep 14 '17 at 10:34
  • Related - https://stackoverflow.com/questions/39707310/select-element-based-on-the-child-of-its-previous-sibling – Paulie_D Sep 14 '17 at 10:35

2 Answers2

2

Use HTML to "connect" the label to the checkbox. This will make a click on the label toggle the state, too. Using the checked state of the checkbox and the sibling selector you can toggle the elements.

<style>
    input[type=checkbox] {
        display: none;
    }
    input[type="checkbox"] + label:before {
        content: "+";
        width: 1em;
        height: 1em;
        display: inline-block;
        margin-right: 5px;
    }
    input[type="checkbox"]:checked + label:before {
        content: "-";
    }
    input[type=checkbox]:checked ~ .elements div.checked,
    input[type=checkbox]:not(:checked) ~ .elements div.unchecked {
        display: block;
    }
    input[type=checkbox]:checked ~ .elements div.unchecked,
    input[type=checkbox]:not(:checked) ~ .elements div.checked {
        display: none;
    }
</style>

<input type="checkbox" id="check" name="check">
<label for="check">My Item</label>
<div class="elements">
    <div class="checked">Checkbox is checked.</div>
    <div class="unchecked">Checkbox is NOT checked.</div>
</div>
Marco
  • 227
  • 1
  • 11
  • This does not show my changed custom checkbox, even when I add my css code to it (of course except the display: none blocks). .. – mrCarnivore Sep 14 '17 at 11:52
  • I updated my answer. Now your custom "checkbox" is shown. Using :after instead of :before you can change the position regarding the label. – Marco Sep 14 '17 at 15:27
  • You're right. Forgot to change + to ~ ... Now it is fine. – Marco Sep 14 '17 at 18:37
0

I have rearranged your HTML structure, replacing label with div class="label".

Instead of using display: none, the checkbox is hidden using opacity. You can then control the area it takes up.

.label {
  position: relative;
  display: inline-block;
}

input[type="checkbox"] {
  opacity: 0;
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
}

input[type="checkbox"]+.label-text:before {
  content: "+";
  width: 1em;
  height: 1em;
  display: inline-block;
  margin-right: 5px;
}

input[type="checkbox"]:checked+.label-text:before {
  content: "-";
}

input[type="checkbox"]:checked~.elements .is_not_checked {
  display: none;
}

input[type="checkbox"]:not(:checked)~.elements .is_checked {
  display: none;
}
<div class="label">
  <input type="checkbox" name="check">
  <span class="label-text">Item Two</span>

  <div class="elements">
    <div class="is_checked">
      Checkbox is checked
    </div>
    <div class="is_not_checked">
      Checkbox is not checked
    </div>
  </div>
</div>
sol
  • 22,311
  • 6
  • 42
  • 59
  • This works. Thanks. I do have one problem with it, though: Somehow the clicking does not work every time. This becomes very apparent when you also add cursor: pointer to the checkbox. 25% of the time the Cursor is not changing when I hover over the label... – mrCarnivore Sep 14 '17 at 16:12
  • @mrCarnivore It seems to work every time for me... Is there a particular area of the label that isn't working for you and I can try replicate? I'm using Chrome on Windows 10 – sol Sep 15 '17 at 08:08
  • I tracked it down but still cannot explain it: when I add: font-size: 25px; to .label the problem starts to appear. I am using Firefox 52.3.0 on Win 7. Same result with IE11 on Win7... – mrCarnivore Sep 15 '17 at 13:25
  • @mrCarnivore ah ok. If you adjust the font you should update the height of the checkbox. Give `input[type="checkbox"]` a height of 25px also. – sol Sep 15 '17 at 13:35
  • Thank you that was it. Would never have thought of that since it sometimes worked and sometimes it did not work at the same coordinates. – mrCarnivore Sep 15 '17 at 13:42