How to style the parent label of a checked radio input
Asked Answered
O

4

11

I need to stylize some radio inputs. I tried some solutions from here but none worked for me. Can someone please take a look at this code and tell me what can I do?

This is the HTML:

<div class="controls">
  <table>
    <tbody>
      <tr>
        <td>
          <label class="radio">
            <input type="radio" name="ad_caroserie" value="0">Berlina
          </label>
        </td>
        <td>
          <label class="radio">
            <input type="radio" name="ad_caroserie" value="1">Break
          </label>
        </td>
        <td>
          <label class="radio">
            <input type="radio" name="ad_caroserie" value="2">Cabrio
          </label>
        </td>
      </tr>
    </tbody>
  </table>
</div>

And the CSS:

label.radio {
  background: #fcb608;
}

.radio input {
  display: none;
}

label.radio input[type="radio"]:checked + label {
  background: #000 !important;
  border: 1px solid green;
  padding: 2px 10px;
}

The CSS doesn't have the desired effect; Can you please help me?

This is some related excerpts of JS:

// If checkboxes or radio buttons, special treatment

  else if (jQ('input[name="'+parentname+'"]').is(':radio')  || jQ('input[name="'+parentname+'[]"]').is(':checkbox')) {
    var find = false;
    var allVals = [];
    jQ("input:checked").each(function() {
      for(var i = 0; i < parentvalues.length; i++) {
        if (jQ(this).val() == parentvalues[i] && find == false) {  
          jQ('#adminForm #f'+child).show();
          jQ('#adminForm #row_'+child).show();
          find = true;
        }
      }
    });
    if (find == false) {
      jQ('#adminForm #f'+child).hide();
      jQ('#adminForm #row_'+child).hide();
      //cleanup child field 
      if (jQ('#adminForm #f'+child).is(':checkbox') || jQ('#adminForm #f'+child).is(':radio')) {
        jQ('#adminForm #f'+child).attr('checked', false);
      }
      else {
        if (cleanValue == true) {
          jQ('#adminForm #f'+child).val('');
        }
      }
    }
  }
  else {
    var find = false;
    for(var i = 0; i < parentvalues.length; i++) {
      if (jQ('#adminForm #f'+parentname).val() == parentvalues[i] && find == false) {  
        jQ('#adminForm #f'+child).show();
        jQ('#adminForm #row_'+child).show();
        find = true;
      }
    }
    if(find == false) {
      jQ('#adminForm #f'+child).hide();
      jQ('#adminForm #row_'+child).hide();
      // cleanup child field 
      if (jQ('#adminForm #f'+child).is(':checkbox') || jQ('#adminForm #f'+child).is(':radio')) {
        jQ('#adminForm #f'+child).attr('checked', false);
      }
      else {
        if (cleanValue == true) {
          jQ('#adminForm #f'+child).val('');
        }
      }
    }
  }
}

function dependency(child,parentname,parentvalue) {
  var parentvalues = parentvalue.split(",");
  // if checkboxes
  jQ('input[name="'+parentname+'[]"]').change(function() {
    checkdependency(child,parentname,parentvalues,true);
    //if checkboxes
    jQ('input[name="'+child+'[]"]').change();
    jQ('input[name="'+child+'"]').change();
    jQ('#'+child).change();
  });
  // if buttons radio
  jQ('input[name="'+parentname+'"]').change(function() {
    checkdependency(child,parentname,parentvalues,true);
    // if checkboxes
    jQ('input[name="'+child+'[]"]').change();
    jQ('input[name="'+child+'"]').change();
    jQ('#'+child).change();
  });
  jQ('#f'+parentname).click(function() {
    checkdependency(child,parentname,parentvalues,true);
    // if checkboxes
    jQ('input[name="'+child+'[]"]').change();
    jQ('input[name="'+child+'"]').change();
    jQ('#f'+child).change();
  });
  checkdependency(child,parentname,parentvalues,false);
}
Orpine answered 26/7, 2017 at 22:7 Comment(6)
Should we assume that your invalid HTML is a typographical error, and in fact correct in production?Partition
Not really understand what u mean.The label is inside a form.Orpine
The input element is not an element as written; it will be interpreted as the plain textContent of the label.Partition
And is a way to change the background when the radio button is checked?Orpine
It appears since your additional code example was added that the first example HTML was incorrect due to a simple typo, and should be fixed.Partition
i remove now the first codeOrpine
P
22

A possibility

At my time of posting, I am not exactly sure what the desired layout should be, but there is one specific problem in the attempted CSS that needs to be addressed.

The adjacent siblings selector:

... separates two selectors and matches the second element only if it immediately follows the first element.

If the <input> is a child of the <label>, it isn't adjacent, so while:

label.radio input[type="radio"]:checked + label

is looking for a label immediately following a :checked input inside a label with the class .radio, nothing like that exists.

To alter the styling of the label in this case, would require a selector that affected the parent, which currently isn't possible.

So, to select the label of the :checked input, we need the label to be adjacent, not the parent.

We can use the for="id" attribute:

A <label> can be associated with a control either by placing the control element inside the <label> element, or by using the for attribute.

As I said, I'm not exactly sure what the desired layout should be, but here's an example using the for attribute, that doesn't look too bad.

div {
  display: inline-block;
  position: relative;
}
label {
  background: #fcb608;
  padding: 2px 10px 2px 1.5em;
  border: 1px solid transparent; /* keeps layout from jumping */
}
input {
  position: absolute;
}
input[type="radio"]:checked + label {
  background: #000;
  border-color: green;
  color: white;
}
<div>
  <input id="id1" type="radio" name="ad_caroserie" value="0">
  <label for="id1" class="radio">Berlina</label>
</div>
<div>
  <input id="id2" type="radio" name="ad_caroserie" value="1">
  <label for="id2" class="radio">Break</label>
</div>
<div>
  <input id="id3" type="radio" name="ad_caroserie" value="2">
  <label for="id3" class="radio">Cabrio</label>
</div>

With <input> as a child of <label>

Using a small JavaScript handler listening for changes to the <form>.

  • If a change is detected, the triggered function checks if an <input type="radio"> was changed, and if so, if it has a <label> as its parentElement.
  • If that's true, it checks to see if there's an identically named <input type="radio"> that's a child of a <label> element with the class .checked.
  • If there is, it removes the class from the <label> before applying the same class to the <label> parent of the <input> target that triggered the whole thing.

let form = document.querySelector( "form" );

form.addEventListener( "change", ( evt ) => {
  let trg = evt.target,
      trg_par = trg.parentElement;
  
  if ( trg.type === "radio" && trg_par &&
       trg_par.tagName.toLowerCase() === "label" ) {
    
    let prior = form.querySelector( 'label.checked input[name="' +
                                    trg.name + '"]' );
    
    if ( prior ) {
      prior.parentElement.classList.remove( "checked" );
    }
    
    trg_par.classList.add( "checked" );
    
  }
}, false );
label {
  background: #fcb608;
  padding: 2px 10px 2px 0;
  border: 1px solid transparent; /* keeps layout from jumping */
}
label.checked {
  background: #000;
  border-color: green;
  color: white;
}
<form>
  <label class="radio"><input type="radio" name="ad_caroserie" value="0">Berlina</label>
  <label class="radio"><input type="radio" name="ad_caroserie" value="1">Break</label>
  <label class="radio"><input type="radio" name="ad_caroserie" value="2">Cabrio</label>
</form>

Without JavaScript things get difficult (per my original explanation of why it's best to use the for attribute in this case).

We can use the appearance property (with prefixes and reasonable support) to effectively hide the user-agent radio GUI, then use the remaining faceless element to build a fake background for the <label>.

This is very hacky and a great deal less dynamic than the default, since some absolute positioning and specific dimensions are required to pull it off.
It kind of works (in most browsers), but is tricky to enforce sitewide.

Something to play around with though :-)

input {
  position: absolute;
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
  width: 5em;
  height: 1.5em;
  z-index: -1;
  background: #fcb608;
  border: 1px solid transparent;
  margin: -.1em -.8em;
  outline: 0;
}
label {
  display: inline-block;
  width: 5em;
  color: white;
  text-shadow: 1px 1px 0px black;
}
input[type="radio"]:checked {
  background: #000;
  border-color: green;
}
<label class="radio"><input type="radio" name="ad_caroserie" value="0">Berlina</label>
<label class="radio"><input type="radio" name="ad_caroserie" value="1">Break</label>
<label class="radio"><input type="radio" name="ad_caroserie" value="2">Cabrio</label>
Partition answered 26/7, 2017 at 23:6 Comment(11)
i cant add an "id" to the radio optionsOrpine
Can you change the HTML at all?Partition
Its a joomla component with a radio field.i will look at the field code to see if i can modify.Orpine
@DinuRaphAlexandru - Added two more examples using different technologies.Partition
Hello Fred.The second option with the JS worked ok.Now the option change the background when selected.I found a JS in the page and i will put on main for you to see it.Orpine
I'm glad one of the solutions works. Note: I just made a small change to the JavaScript that will make it less susceptible to possible error; please update your usage.Partition
Did u seen the JS code i put?Is not possible to modify there?Orpine
Sorry, no I didn't see that until now. I will have a good look in a couple of hours since I must log off to do other stuff first.Partition
@DinuRaphAlexandru - without knowing when or how that jQuery is called, I wouldn't know the best way to include the functionality I've provided. As long as the code is executed after the <form> has loaded, and before it is used, you should be able to include the code pretty much anywhere. It would be simplest to add it in a <script> under the <form>, and make sure the querySelector() is specific enough to grab the form you want to affect. For multiple forms, or to make these changes site wide, other concerns come in to play; please post another question for help with those issues.Partition
The second variant solves my problem.Hope this post will be useful for anybody who have same issue.Orpine
Clever solution - reddit.com/r/css/comments/15cgf26/… "... Basically, you don't want to style the label at all. Put the input inside the label with another div or span or whatever element you want to style, and that will be the one you style. ..."Castor
E
5

Just use jQuery with a new css class "selected" something like this:

on start:

$("input[name='ad_caroserie']:checked").parent().addClass("selected");

and onchange:

$('input[type=radio][name=ad_caroserie]').change(function() {
  $("input[name='ad_caroserie']").parent().removeClass("selected");
  $("input[name='ad_caroserie']:checked").parent().addClass("selected");
  // console.log($("input[name='ad_caroserie']:checked").val());
});
Expiate answered 11/1, 2018 at 10:3 Comment(0)
T
1

After trying so many time with pure HTML and CSS. I am settling with this simple solution with JavaScript. I think this will help.

function check(btn) {
  let label = btn.children;
  label[0].checked = true;
}
.lib-radio {
  color: #1e1e1e;
  font-size: 1.0em;
  border-radius: 31px;
  font-weight: 400;
  width: 450px;
  height: 40px;
  border: 2px solid black;
  padding: 0.5em;
  font-family: Lato;
  margin: 10px 0 0 0;
}

.lib-radio:hover {
  background-color: #000;
  color: #FFF;
}
<div class="lib-one-input">

  <p class="lib-form-label">Select your gender</p>

  <div class="lib-radio" onclick="check(this)">

    <input id="s1yes" type="radio" name="mcq1" value="male">

    <label for="s1yes"> Yes, our researchers authored it</label><br />

  </div>

  <div class="lib-radio" onclick="check(this)">

    <input id="s1no" type="radio" name="mcq1" value="female">

    <label for="s1no"> No, we didn&#39t author it </label><br />

  </div>

</div>
Teller answered 9/7, 2019 at 22:3 Comment(0)
F
-1
<form id="button-form">
  <fieldset id="button-set">
    <label for="button-1">
      <input type="radio" id="button-1" name="button-group"/>
    </label>

    <label for="button-2">
      <input type="radio" id="button-2" name="button-group"/>
    </label>

    <label for="button-3">
      <input type="radio" id="button-3" name="button-group"/>
    </label>
  </fieldset>
</form>

<style>
  #button-set label > * {
    opacity: 0; <!-- hideing the radio buttons -->
  }
</style>

<script>
  function setColor(color) {
    document.getElementsByName("button-group").forEach(node => {
      node.checked === true
        ? (node.parentElement.style.background = color)
        : (node.parentElement.style.background = "rgba(0, 0, 0, 0.5)");
    });
  }

  window.onload = () => {
    document.getElementById("button-form").onchange = evt => {
      switch (evt.target) {
        case document.getElementsById("button-1"):
          setColor("rgba(0, 150, 0, 0.5)");
          break;
        case document.getElementsById("button-2"):
          setColor("rgba(250, 200, 0, 0.5)");
          break;
        case document.getElementsById("button-3"):
          setColor("rgba(250, 0, 0, 0.5)");
          break;
      }
    };
  };
</script>
Fugitive answered 15/7, 2020 at 10:22 Comment(1)
Please add some info on what you have changed. see: stackoverflow.com/help/how-to-answerSpradling

© 2022 - 2024 — McMap. All rights reserved.