168

I want to add a style to a radio button's selected label:

HTML:

<div class="radio-toolbar">
 <label><input type="radio" value="all" checked>All</label>
 <label><input type="radio" value="false">Open</label>
 <label><input type="radio" value="true">Archived</label>
</div>

CSS

.radio-toolbar input[type="radio"] {display:none;}
.radio-toolbar label {
    background:Red;
    border:1px solid green;
    padding:2px 10px;
}
.radio-toolbar label + input[type="radio"]:checked { 
    background:pink !important;
}

Any ideas what I'm doing wrong?

Nikola K.
  • 7,093
  • 13
  • 31
  • 39
AnApprentice
  • 108,152
  • 195
  • 629
  • 1,012

8 Answers8

356

.radio-toolbar input[type="radio"] {
  display: none;
}

.radio-toolbar label {
  display: inline-block;
  background-color: #ddd;
  padding: 4px 11px;
  font-family: Arial;
  font-size: 16px;
  cursor: pointer;
}

.radio-toolbar input[type="radio"]:checked+label {
  background-color: #bbb;
}
<div class="radio-toolbar">
  <input type="radio" id="radio1" name="radios" value="all" checked>
  <label for="radio1">All</label>

  <input type="radio" id="radio2" name="radios" value="false">
  <label for="radio2">Open</label>

  <input type="radio" id="radio3" name="radios" value="true">
  <label for="radio3">Archived</label>
</div>

First of all, you probably want to add the name attribute on the radio buttons. Otherwise, they are not part of the same group, and multiple radio buttons can be checked.

Also, since I placed the labels as siblings (of the radio buttons), I had to use the id and for attributes to associate them together.

Zze
  • 18,229
  • 13
  • 85
  • 118
Šime Vidas
  • 182,163
  • 62
  • 281
  • 385
  • 2
    @Johncl That's true. IE8 does not implement the `:checked` selector. – Šime Vidas Dec 07 '12 at 14:30
  • If i wish to select neither input[type="radio"] or input[type="checkbox"]. Which is the correct syntax to do it in only one rule and avoid doing: input[type="radio"], input[type="checkbox"] – fabregas88 Aug 15 '13 at 18:32
  • @fabregas88 You could add a CSS class to those elements, and then `.foo { ... }` – Šime Vidas Aug 15 '13 at 21:12
  • @ŠimeVidas right, that's one correct way. However I was looking something like this: input[type="radio|checkbox"], which is the correct syntax to do it this way? – fabregas88 Aug 16 '13 at 13:10
  • @fabregas88 That should be a new question, not a comment on a two year old one. The answer is "no" though. – Mr Lister Aug 23 '13 at 06:08
  • 10
    You just killed keyboard access! hope all your users are able bodied. ...now, if you just keep the radio button there, without using `display:none;` then the browsers will make it work with keyboard just fine. – gcb Jul 29 '15 at 22:35
  • 1
    @gcb The question was how to hide the standard radio buttons. I’ve made this prototype https://jsbin.com/miwati/edit?html,css,output. The radio buttons are absolutely positioned behind the labels. Probably not the best approach though. – Šime Vidas Aug 02 '15 at 15:58
  • @ŠimeVidas nice. that leads to lots of for-display-hacks-only-html, but i also can't see how to do it better and still have keyboard accessibility. – gcb Aug 02 '15 at 18:51
35

If you really want to put the checkboxes inside the label, try adding an extra span tag, eg.

HTML

<div class="radio-toolbar">
 <label><input type="radio" value="all" checked><span>All</span></label>
 <label><input type="radio" value="false"><span>Open</span></label>
 <label><input type="radio" value="true"><span>Archived</span></label>
</div>

CSS

.radio-toolbar input[type="radio"]:checked ~ * { 
    background:pink !important;
}

That will set the backgrounds for all siblings of the selected radio button.

iainbeeston
  • 1,851
  • 1
  • 21
  • 20
  • 2
    I preferred this approach, although I used a different selector ('+' as mentioned below and [in this question](http://stackoverflow.com/q/14592768/957950) as I wanted to style just the selected item. This allowed me to not worry about the `for` attributes. – brichins Nov 05 '15 at 18:08
5

You are using an adjacent sibling selector (+) when the elements are not siblings. The label is the parent of the input, not it's sibling.

CSS has no way to select an element based on it's descendents (nor anything that follows it).

You'll need to look to JavaScript to solve this.

Alternatively, rearrange your markup:

<input id="foo"><label for="foo">…</label>
Quentin
  • 914,110
  • 126
  • 1,211
  • 1,335
3

You can add a span to your html and css .

Here's an example from my code ...

HTML ( JSX ):

<input type="radio" name="AMPM" id="radiostyle1" value="AM" checked={this.state.AMPM==="AM"} onChange={this.handleChange}/>  
<label for="radiostyle1"><span></span> am  </label>

<input type="radio" name="AMPM" id="radiostyle2" value="PM" checked={this.state.AMPM==="PM"} onChange={this.handleChange}/>
<label for="radiostyle2"><span></span> pm  </label>

CSS to make standard radio button vanish on screen and superimpose custom button image:

input[type="radio"] {  
    opacity:0;                                      
}

input[type="radio"] + label {
    font-size:1em;
    text-transform: uppercase;
    color: white ;  
    cursor: pointer;
    margin:auto 15px auto auto;                    
}

input[type="radio"] + label span {
    display:inline-block;
    width:30px;
    height:10px;
    margin:1px 0px 0 -30px;                       
    cursor:pointer;
    border-radius: 20%;
}


input[type="radio"] + label span {
    background-color: #FFFFFF 
}


input[type="radio"]:checked + label span{
     background-color: #660006;  
}
Jon Saw
  • 7,599
  • 6
  • 48
  • 57
3

Just use label:focus-within {} to style a label with a checked radio or checkbox.

1

Here's an accessible solution

label {
  position: relative;
}

label input {
  position: absolute;
  opacity: 0;
}

label:focus-within {
  outline: 1px solid orange;
}
<div class="radio-toolbar">
  <label><input type="radio" value="all" checked>All</label>
  <label><input type="radio" value="false">Open</label>
  <label><input type="radio" value="true">Archived</label>
</div>
WofWca
  • 571
  • 3
  • 11
0

As there is currently no CSS solution to style a parent, I use a simple jQuery one here to add a class to a label with checked input inside it.

$(document).on("change","input", function(){
 $("label").removeClass("checkedlabel");
 if($(this).is(":checked")) $(this).closest("label").addClass("checkedlabel");
});

Don't forget to give the pre-checked input's label the class checkedlabel too

Fanky
  • 1,673
  • 1
  • 18
  • 20
  • You don't need JS in order to style a label, you can target it directly in CSS. – kahlan88 Sep 05 '22 at 15:52
  • @kahlan88 You can't. You can't target it directly in CSS when the label is parent of input. It is common that having label as parent is needed. – Phoca Jul 30 '23 at 01:16
0

As TimStieffenhofer mentioned in their answer, the easiest way is to have the input field as a child of the label and use the :focus-within pseudo-class on the label.

If you want to hide your radio button and set the input to hidden or display none, that will no longer work. The work around is to give the input field a z-index of -1 (or any z-index lower than the parent label).

cigien
  • 57,834
  • 11
  • 73
  • 112