210

If I have a radio group with buttons:

Image 1

... how can I show only images in the select option instead of the buttons, e.g.

enter image description here

Vignesh Pichamani
  • 7,950
  • 22
  • 77
  • 115
  • Can we see a live link or a jsFiddle for your code? – Nitesh Jul 09 '13 at 06:45
  • 3
    Create a radio button set and put them in a hidden div. On image click set that particular radio button checked means on first image click set your first radio button checked and similarly for other two. If you didn't got I can explain via code too. – Chiragit007 Jul 09 '13 at 06:46
  • Its not working here can you suggest http://stackoverflow.com/questions/42736745/image-radio-button-giving-unexpected-on-second-click – Code Guy Mar 12 '17 at 01:51

10 Answers10

488
  • Wrap radio and image in <label>
  • Hide radio button (Don't use display:none or visibility:hidden since such will impact accessibility)
  • Target the image next to the hidden radio using Adjacent sibling selector +
  • Don’t forget to provide alternative text in the alt attribute, especially since it functions as the radio button’s label

/* HIDE RADIO */
[type=radio] { 
  position: absolute;
  opacity: 0;
  width: 0;
  height: 0;
}

/* IMAGE STYLES */
[type=radio] + img {
  cursor: pointer;
}

/* CHECKED STYLES */
[type=radio]:checked + img {
  outline: 2px solid #f00;
}
<label>
  <input type="radio" name="test" value="small" checked>
  <img src="https://via.placeholder.com/40x60/0bf/fff&text=A" alt="Option 1">
</label>

<label>
  <input type="radio" name="test" value="big">
  <img src="https://via.placeholder.com/40x60/b0f/fff&text=B" alt="Option 2">
</label>

Don't forget to add a class to your labels and in CSS use that class instead.


Custom styles and animations

Here's an advanced version using the <i> element and the ::after pseudo-element:

CSS custom radio and checkbox

body{color:#444;font:100%/1.4 sans-serif;}


/* CUSTOM RADIO & CHECKBOXES
   http://stackoverflow.com/a/17541916/383904 */
.rad,
.ckb{
  cursor: pointer;
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
}
.rad > input,
.ckb > input{ /* HIDE ORG RADIO & CHECKBOX */
  position: absolute;
  opacity: 0;
  width: 0;
  height: 0;
}
/* RADIO & CHECKBOX STYLES */
/* DEFAULT <i> STYLE */
.rad > i,
.ckb > i{ 
  display: inline-block;
  vertical-align: middle;
  height: 16px;
  transition: 0.2s;
  box-shadow: inset 0 0 0 8px #fff;
  border: 1px solid gray;
  background: gray;
}
.rad > i {
  width:  16px;
  border-radius: 50%;
}
.ckb > i {
  width: 25px;
  border-radius: 3px;
}
.rad:hover > i{ /* HOVER <i> STYLE */
  box-shadow: inset 0 0 0 3px #fff;
  background: gray;
}
.rad > input:focus + i { /* FOCUS <i> STYLE */
  outline: 1px solid blue;
}
.rad > input:checked + i{ /* (RADIO CHECKED) <i> STYLE */
  box-shadow: inset 0 0 0 3px #fff;
  background: orange;
}
/* CHECKBOX */
.ckb > input + i::after{
  content: "";
  display: block;
  height: 12px;
  width:  12px;
  margin: 2px;
  border-radius: inherit;
  transition: inherit;
  background: gray;
}
.ckb > input:focus + i {
  outline: 1px solid blue;
}
.ckb > input:checked + i::after{ /* (RADIO CHECKED) <i> STYLE */
  margin-left: 11px;
  background:  orange;
}
<label class="rad">
  <input type="radio" name="rad1" value="a">
  <i></i> Radio 1
</label>
<label class="rad">
  <input type="radio" name="rad1" value="b" checked>
  <i></i> Radio 2
</label>

<br>

<label class="ckb">
  <input type="checkbox" name="ckb1" value="a" checked>
  <i aria-hidden="true"></i> Checkbox 1
</label>
<label class="ckb">
  <input type="checkbox" name="ckb2" value="b">
  <i aria-hidden="true"></i> Checkbox 2
</label>
Andy
  • 4,783
  • 2
  • 26
  • 51
Roko C. Buljan
  • 196,159
  • 39
  • 305
  • 313
  • 11
    +1 for the pseudo selector, I think I've used JavaScript in the past to check for selected! That'll teach me... – zik Jul 09 '13 at 07:03
  • 3
    visibility hidden means that it is not click-able, and position absolute takes it out of the document flow – 99 Problems - Syntax ain't one Dec 05 '14 at 09:14
  • 1
    This is an excellent answer. May I add that the same works with `type="checkbox"` as well. – Wtower Jan 02 '15 at 11:21
  • ok this is nice.. works great, apparently works on IE too, but actually it isn't. the image behaves correctly but when the form is submitted, there is no thumbnail selection. I guess i am using the new IE that comes with Win 8.1. Any idea? – Junaid Rehman Feb 20 '15 at 22:18
  • @JunaidRehman can you please test this one in IE? http://jsbin.com/pafifi/2/edit?html,css,js,output do some stuff and click TEST to see the serialized form output. Thx. – Roko C. Buljan Feb 21 '15 at 10:52
  • This solution doesn't work in IE if the inputs are contained inside a
    , like this: http://jsbin.com/wizajavuhi/1/edit - Anybody knows how to fix it?
    – empz Mar 06 '15 at 17:18
  • [here](http://stackoverflow.com/questions/7086098/how-to-create-radio-button-with-images) is another image next to radio button , which is checked via image too, hope helps someone. – Shaiju T Oct 31 '15 at 14:50
  • 3
    Late to the party, but be careful with this. `Visibility:hidden` will hide the inputs from screen reader and a big no no from accessibility standpoint. – DPac Mar 22 '16 at 15:10
  • @DPac thanks, but since `display:none;` will have issues with form inputs values submit, do you have any suggestion? (perhaps using negative left value like i.e: `left:-2000px; position:absolute`)... ? Using `aria` labels on the `img` (or the replacing) element should work in that case... have you thought about that? – Roko C. Buljan Mar 22 '16 at 15:12
  • I'm still exploring options as of now, as this is one of the new requirements that I have. Using negative value would work. Right now I'm leaning towards combining `appearance:none` and setting 1px height/width to the inputs. It will leave a small dot on top left corner on non webkit browsers, but for my case it's acceptable and much better than being non-accessible. – DPac Mar 22 '16 at 15:54
  • @DPac for screen readers, read more about the `aria` label. It's also used exactly when an element that should perform an action is replaced by another one - still making the page comprehensible for scr.reader programs. – Roko C. Buljan Mar 22 '16 at 16:17
  • @RokoC.Buljan Can we replace `label` with any other tag? – laviku Jun 18 '16 at 16:11
  • what is the correct and cross browser solution visibility: hidden; or display:none; because on jsbin has display on stackoverflow visibility – al404IT Sep 22 '16 at 08:32
  • @al404IT thanks for the input :) visibility should be used. Updated jsBin accordingly. Thanks – Roko C. Buljan Sep 22 '16 at 09:30
  • not working here, http://stackoverflow.com/questions/42736745/image-radio-button-giving-unexpected-on-second-click – Code Guy Mar 12 '17 at 01:52
  • I'm curios why the i tag is used instead of another like span etc.? Is it best practicse since font-awsome uses it too? – Sven Rojek Apr 05 '17 at 08:26
  • No particular case... you're very welcome to use ``. I don't remember if Font-Awesome was my inspiration for using `` at the time... but it has less characters for sure :) – Roko C. Buljan Apr 05 '17 at 13:46
  • @RokoC.Buljan Thank you for your answer, but how to show HTML5 required error messages. That error messages not visible – Gayan May 30 '17 at 09:08
  • This won't work in IE11 as mentioned in this bug: https://stackoverflow.com/questions/20198137/image-label-for-input-in-a-form-not-clickable-in-ie11/20222705 You'll also have to add label > input + img { pointer-events: none; } not sure how it works though – Rahul Gupta Dec 21 '17 at 09:01
  • Can anyone here help with this https://stackoverflow.com/questions/59681676/rails-use-image-instead-of-radio-buttons – mrateb Jan 10 '20 at 12:39
  • For me the images are not clickable. A cursor is displayed correctly. But still I Can not click on the image – mrateb Jan 10 '20 at 12:42
  • @mrateb strange it works for everyone else... Any specific browser? Are you talking about the example above? – Roko C. Buljan Jan 10 '20 at 13:34
  • Yes I understand, which is why I'm surprised. Its not working for me for chrome and firefox. Now the difference for me is that I'm using rails, so technically writing erb files, but he end result should be the same, since even the results from inspect are the same as we have here. My code is here https://stackoverflow.com/questions/59681676/rails-use-image-instead-of-radio-buttons ill be grateful if you could take a look – mrateb Jan 10 '20 at 14:15
  • @mrateb removing '/' from input and img tag should work. i had same problem. for this thing to work putting at foremost outside instead of div, button, or any other tags is the key. – hyukkyulee Aug 09 '21 at 03:16
125

Example:

Heads up! This solution is CSS-only.

Credit-card selector, the MasterCard on the modded demo is hovered.

I recommend you take advantage of CSS3 to do that, by hidding the by-default input radio button with CSS3 rules:

.options input{
    margin:0;padding:0;
    -webkit-appearance:none;
       -moz-appearance:none;
            appearance:none;
}

I just make an example a few days ago.

Richard Cotrina
  • 2,525
  • 1
  • 23
  • 23
  • 1
    This was great! I integrated it to a ASP.NET Form and it worked like a charm :) – Gus Apr 08 '15 at 19:01
  • This example does not work in Firefox 49.0.2 under XUbuntu 16.04.1 – Sergey Kudriavtsev Nov 15 '16 at 21:54
  • @SergeyKudriavtsev maybe the code needs and update (this answer is from 2013). Thankfully the code is open for anyone to improve it. I'll take a look into it soon. Cheers. – Richard Cotrina Dec 23 '16 at 14:31
  • Works fine for me in Firefox 60, Windows 10. – Trevor Jun 04 '18 at 07:37
  • I have this working for a set of 3 smiley faces. Now I need to have multiple rows on one form, each with their own set of smiley faces. My problem is that when one row is changed, they all change. Any ideas what part needs to be modified to accomplish this? – dave317 Nov 27 '18 at 20:41
  • Ignore my last comment, figured it out using the input id and matching it to the for= field in the label – dave317 Nov 27 '18 at 20:48
  • Fantastic solution!! – Ed DeGagne Feb 07 '19 at 20:09
  • 1
    message validations browser dont work. but you can fix remove selectors: "cc-selector input" and "cc-selector-2 input" and add this code: input[type="radio"] { opacity: 0; position: absolute; z-index: -1; } – oniram Sep 18 '20 at 20:15
22

You can use CSS for that.

HTML (only for demo, it is customizable)

<div class="button">
    <input type="radio" name="a" value="a" id="a" />
    <label for="a">a</label>
</div>
<div class="button">
    <input type="radio" name="a" value="b" id="b" />
    <label for="b">b</label>
</div>
<div class="button">
    <input type="radio" name="a" value="c" id="c" />
    <label for="c">c</label>
</div>
...

CSS

input[type="radio"] {
    display: none;
}
input[type="radio"]:checked + label {
    border: 1px solid red;
}

jsFiddle

Community
  • 1
  • 1
Fracsi
  • 2,274
  • 15
  • 24
6

Keep radio buttons hidden, and on clicking of images, select them using JavaScript and style your image so that it look like selected. Here is the markup -

<div id="radio-button-wrapper">
    <span class="image-radio">
        <input name="any-name" style="display:none" type="radio"/>
        <img src="...">
    </span>
    <span class="image-radio">
        <input name="any-name" style="display:none" type="radio"/>
        <img src="...">
    </span>
</div>

and JS

 $(".image-radio img").click(function(){
     $(this).prev().attr('checked',true);
 })

CSS

span.image-radio input[type="radio"]:checked + img{
    border:1px solid red;
}
Moazzam Khan
  • 3,130
  • 2
  • 20
  • 35
5

Just using a class to only hide some...based on https://stackoverflow.com/a/17541916/1815624

/* HIDE RADIO */
.hiddenradio [type=radio] { 
  position: absolute;
  opacity: 0;
  width: 0;
  height: 0;
}

/* IMAGE STYLES */
.hiddenradio [type=radio] + img {
  cursor: pointer;
}

/* CHECKED STYLES */
.hiddenradio [type=radio]:checked + img {
  outline: 2px solid #f00;
}
<div class="hiddenradio">
<label>
  <input type="radio" name="test" value="small" checked>
  <img src="http://placehold.it/40x60/0bf/fff&text=A">
</label>

<label>
  <input type="radio" name="test" value="big">
  <img src="http://placehold.it/40x60/b0f/fff&text=B">
</label>
</div>

<div class="">
<label>
  <input type="radio" name="test" value="small" checked>
  <img src="http://placehold.it/40x60/0bf/fff&text=A">
</label>

<label>
  <input type="radio" name="test" value="big">
  <img src="http://placehold.it/40x60/b0f/fff&text=B">
</label>
</div>
CrandellWS
  • 2,708
  • 5
  • 49
  • 111
1

Here is a simple jQuery UI solution based on the example here:

http://jqueryui.com/button/#radio

Modified code:

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>jQuery UI Button - Radios</title>
  <link rel="stylesheet" href="//code.jquery.com/ui/1.11.3/themes/smoothness/jquery-ui.css">
  <script src="//code.jquery.com/jquery-1.10.2.js"></script>
  <script src="//code.jquery.com/ui/1.11.3/jquery-ui.js"></script>
  <link rel="stylesheet" href="/resources/demos/style.css">
  <script>
  $(function() {
    $( "#radio" ).buttonset();
  });
  </script>
</head>
<body>

<form>
  <div id="radio">
    <input type="radio" id="radio1" name="radio"><label for="radio1"><img src="image1.gif" /></label>
    <input type="radio" id="radio2" name="radio" checked="checked"><label for="radio2"><img src="image2.gif" /></label>
    <input type="radio" id="radio3" name="radio"><label for="radio3"><img src="image3.gif" /></label>
  </div>
</form>

</body>
</html>

jQueryUI takes care of the image background so you know which button is checked.

Beware: If you want to set a button to checked or unchecked via Javascript, you must call the refresh function:

        $('#radio3').prop('checked', true).button("refresh");
atmelino
  • 2,887
  • 2
  • 20
  • 15
1

Images can be placed in place of radio buttons by using label and span elements.

   <div class="customize-radio">
        <label>Favourite Smiley</label><br>
        <label for="hahaha">
        <input type="radio" name="smiley" id="hahaha">
        <span class="haha-img"></span>
        HAHAHA
        </label>
        <label for="kiss">
        <input type="radio" name="smiley" id="kiss">
        <span class="kiss-img"></span>
        Kiss
        </label>
        <label for="tongueOut">
        <input type="radio" name="smiley" id="tongueOut">
        <span class="tongueout-img"></span>
        TongueOut
        </label>
    </div>

Radio button should be hidden,

.customize-radio label > input[type = 'radio'] {
    visibility: hidden;
    position: absolute;
}

Image can be given in the span tag,

.customize-radio label > input[type = 'radio'] ~ span{
    cursor: pointer;
    width: 27px;
    height: 24px;
    display: inline-block;
    background-size: 27px 24px;
    background-repeat: no-repeat;
}
.haha-img {
    background-image: url('hahabefore.png');
}

.kiss-img{
    background-image: url('kissbefore.png');
}
.tongueout-img{
    background-image: url('tongueoutbefore.png');
}

To change the image on click of radio button, add checked state to the input tag,

.customize-radio label > input[type = 'radio']:checked ~ span.haha-img{
     background-image: url('haha.png');
}
.customize-radio label > input[type = 'radio']:checked ~ span.kiss-img{
    background-image: url('kiss.png');
}
.customize-radio label > input[type = 'radio']:checked ~ span.tongueout-img{
        background-image: url('tongueout.png');
}

If you have any queries, Refer to the following link, As I have taken solution from the below blog, http://frontendsupport.blogspot.com/2018/06/cool-radio-buttons-with-images.html

Beginner
  • 21
  • 3
0

Here is very simple example

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

input[type="radio"] + label
{
    background-image:url(http://www.clker.com/cliparts/c/q/l/t/l/B/radiobutton-unchecked-sm-md.png);
    background-size: 100px 100px;
    height: 100px;
    width: 100px;
    display:inline-block;
    padding: 0 0 0 0px;
    cursor:pointer;
}

input[type="radio"]:checked + label
{
    background-image:url(http://www.clker.com/cliparts/M/2/V/6/F/u/radiobutton-checked-sm-md.png);
}
<div>
  <input type="radio" id="shipadd1" value=1 name="address" />
  <label for="shipadd1"></label>
  value 1
</div>

<div>
  <input type="radio" id="shipadd2" value=2 name="address" />
  <label for="shipadd2"></label>
  value 2
</div>

Demo: http://jsfiddle.net/La8wQ/2471/

This example based on this trick: https://css-tricks.com/the-checkbox-hack/

I tested it on: chrome, firefox, safari

Kamil Kiełczewski
  • 85,173
  • 29
  • 368
  • 345
0
$spinTime: 3;
html, body { height: 100%; }
* { user-select: none; }
body {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    font-family: 'Raleway', sans-serif;
    font-size: 72px;
    input {
        display: none;
        + div > span {
            display: inline-block;
            position: relative;
            white-space: nowrap;
            color: rgba(#fff, 0);
            transition: all 0.5s ease-in-out;
            span {
                display: inline-block;
                position: absolute;
                left: 50%;
                text-align: center;
                color: rgba(#000, 1);
                transform: translateX(-50%);
                transform-origin: left;
                transition: all 0.5s ease-in-out;
                &:first-of-type {
                    transform: rotateY(0deg) translateX(-50%);
                }
                &:last-of-type {
                    transform: rotateY(0deg) translateX(0%) scaleX(0.75) skew(23deg,0deg);
                }
            }
        }
        &#fat:checked ~ div > span span {
            &:first-of-type {
                transform: rotateY(0deg) translateX(-50%);
            }
            &:last-of-type {
                transform: rotateY(0deg) translateX(0%) scaleX(0.75) skew(23deg,0deg);
            }
        }
        &#fit:checked ~ div > span {
            margin: 0 -10px;
            span {
                &:first-of-type {
                    transform: rotateY(90deg) translateX(-50%);
                }
                &:last-of-type {
                    transform: rotateY(0deg) translateX(-50%) scaleX(1) skew(0deg,0deg);
                }
            }
        }
        + div + div {
            width: 280px;
            margin-top: 10px;
            label {
                display: block;
                padding: 20px 10px;
                text-align: center;
                transition: all 0.15s ease-in-out;
                background: #fff;
                border-radius: 10px;
                box-sizing: border-box;
                width: 48%;
                font-size: 64px;
                cursor: pointer;
                &:first-child {
                    float: left;
                    box-shadow:
                        inset 0 0 0 4px #1597ff,
                        0 15px 15px -10px rgba(darken(#1597ff, 10%), 0.375);
                }
                &:last-child { float: right; }
            }
        }
        &#fat:checked ~ div + div label {
            &:first-child {
                box-shadow:
                    inset 0 0 0 4px #1597ff,
                    0 15px 15px -10px rgba(darken(#1597ff, 10%), 0.375);
            }
            &:last-child {
                box-shadow:
                    inset 0 0 0 0px #1597ff,
                    0 10px 15px -20px rgba(#1597ff, 0);
            }
        }
        &#fit:checked ~ div + div label {
            &:first-child {
                box-shadow:
                    inset 0 0 0 0px #1597ff,
                    0 10px 15px -20px rgba(#1597ff, 0);
            }
            &:last-child {
                box-shadow:
                    inset 0 0 0 4px #1597ff,
                    0 15px 15px -10px rgba(darken(#1597ff, 10%), 0.375);
            }
        }
    }
}


<input type="radio" id="fat" name="fatfit">
<input type="radio" id="fit" name="fatfit">
<div>
    GET F<span>A<span>A</span><span>I</span></span>T
</div>
<div>
    <label for="fat"></label>
    <label for="fit"></label>
</div>
0

This works for me:

input[type="radio"] {
    margin-right: 1em;
    appearance: none;
    width: 12px;
    height: 12px;
    background-image: url("checkbox_off.gif");       
}

input[type="radio"]:checked {
    background-image: url("checkbox_on.gif");           
}