Animated Checkboxes and Radio Buttons with SVG

By animating an SVG path with JavaScript, we can do many fancy things. Today we want to show you some effects for checkboxes and radio buttons. The idea is to hide the inputs, use pseudo-elements to create a more appealing style and then animate the SVG paths once an input is selected.

Today we’d like to share some fancy “check” animations for checkboxes and radio buttons with you. The idea is to animate an SVG to create a nice visual effect for selecting a checkbox or radio input. There are many possibilities for the animated graphic, like a cross, a check mark, a circle and so on. The technique for animating the SVG paths is by Jake Archibald and you can read how it works in detail in his article Animated line drawing in SVG.

Please note that this is just a proof-of-concept and not a complete solution. The SVG path transition might not work in all browsers, especially mobile ones.

For the custom checkbox or radio button we use the ::before pseudo-element of the label and we hide the input by setting the opacity to 0. It’s actually there, on top of the pseudo-element, so that we can simply click on it and retain the default input selection behavior. We also make the label clickable by setting the value of the for attribute to the ID of the input.

Initially, we also add the necessary SVG elements after the inputs with JavaScript. They won’t be visible because their paths are empty; once we select an input, we’ll animate the paths with an appropiate transition.

Here is an example of a form structure:

<form class="ac-custom ac-checkbox ac-cross">
	<h2>How do you collaboratively administrate empowered markets via plug-and-play networks?</h2>
	<ul>
		<li><input id="cb1" name="cb1" type="checkbox"><label for="cb1">Efficiently unleash information</label></li>
		<li><input id="cb2" name="cb2" type="checkbox"><label for="cb2">Quickly maximize timely deliverables</label></li>
		<li><input id="cb3" name="cb3" type="checkbox"><label for="cb3">Dramatically maintain solutions</label></li>
		<li><input id="cb4" name="cb4" type="checkbox"><label for="cb4">Completely synergize relationships</label></li>
		<li><input id="cb5" name="cb5" type="checkbox"><label for="cb5">Professionally cultivate customer service</label></li>
	</ul>
</form>

We are using an unordered list with the inputs and labels.

The core styles for making the input invisible and creating the box out of the pseudo-element is the following:

.ac-custom label {
	display: inline-block;
	position: relative;
	font-size: 2em;
	padding: 0 0 0 80px;
	vertical-align: top;
	color: rgba(0,0,0,0.2);
	cursor: pointer;
	transition: color 0.3s;
}

.ac-custom input[type="checkbox"],
.ac-custom input[type="radio"],
.ac-custom label::before {
	width: 50px;
	height: 50px;
	top: 50%;
	left: 0;
	margin-top: -25px;
	position: absolute;
	cursor: pointer;
}

.ac-custom input[type="checkbox"],
.ac-custom input[type="radio"] {
	opacity: 0;
	display: inline-block;
	vertical-align: middle;
	z-index: 100;
}

.ac-custom label::before {
	content: '';
	border: 4px solid #fff;
	transition: opacity 0.3s;
}

When an input get’s checked, we’ll animate the opacity of the “pseudo-checkbox” and the color of the label:

.ac-custom input[type="checkbox"]:checked + label,
.ac-custom input[type="radio"]:checked + label {
	color: #fff;
} 

.ac-custom input[type="checkbox"]:checked + label::before,
.ac-custom input[type="radio"]:checked + label::before {
	opacity: 0.8;
}

As you can see, we are using the adjacent sibling selector for targeting the label and its pseudo element. This can be buggy in some browsers so you might want to add the input inside of the label like shown in example B on the label Wiki page: HTML/Elements/label – W3C Wiki.

We noticed a small glitch for the last example in Firefox (24.0) on Mac. For some reason the end of the SVG drawing is shortly shown before it gets animated.

Here are a couple of screenshots of some of the styles:

A hand-drawn circle around a radio button:
AnimatedCheckboxes01

The classic check mark for checkboxes:
AnimatedCheckboxes02

A fill drawing for a radio button:
AnimatedCheckboxes03

The filler text in the demo is from Corporate Ipsum.

I hope you enjoyed these animations and find them inspiring and useful!

Tagged with:

Manoela Ilic

Manoela is the main tinkerer at Codrops. With a background in coding and passion for all things design, she creates web experiments and keeps frontend professionals informed about the latest trends.

Stay up to date with the latest web design and development news and relevant updates from Codrops.

Feedback 57

Comments are closed.
  1. On firefox 24 on W8 I have some issues too =/
    it blinks =/
    But I’m sure it’s awesome anyway ^^ as always

  2. Love these examples!

    Though I’ll add that they don’t work well in Firefox 24.0 on Windows 7 either. Once selected the SVG becomes visible, and then appears to flicker as the animation runs.

  3. Once again, OUTSTANDING-

    I would have never thought of doing it, and now that I see it, it makes total sense, and I wish i could see it used on real websitesβ€”it just adds so much to the user experience

    Great job +10000000

    -vlado the cat

  4. I find it kind of hacky to be putting the checkbox style on the label, when you’re styling the input, not the label. I am aware that you can’t use the :before or :after pseudoselectors on the input, but that’s why I would have taken a different approach entirely, overlapping the old radio with the modified style: position: absolute; z-index: 9, left: 0; top: 0;. That way, non-supporting browsers for :before and :after would display the radios natively, and you wouldn’t get an invisible radio (bad accessibility).

    The other point I’d make is that you may not always have a label, and sometimes, we use hacks to hide them. Without a label, these styles would fail, as we are using the adjacent selector.

  5. Hi Mary,
    your demo looks really beautiful but your js isn’t that cool.
    I took a few minutes to optimize your javascript code (even if I am sure that the your code logic is not perfect yet ) feel free to update your demo if you like it.
    You can check my fixed version on here https://gist.github.com/GianlucaGuarini/6997522

    have a nice day πŸ™‚

  6. Very cool, and it gets better using only CSS, like a:
    input:checked~label~svg path:nth-child(1)
    {
    stroke-dasharray: 113.1370849609375px, 113.1370849609375px;
    transition: all 0.2s ease-in-out 0s;
    }

    input:checked~label~svg path:nth-child(2)
    {
    stroke-dasharray: 113.1370849609375px, 113.1370849609375px;
    transition: all 0.2s ease-in-out 0.2s;
    }

  7. Hello Mary Lou,
    I wanted to ask if there is a way to apply different animations within the same form.
    I have a form in which there are both checkboxes and radio buttons. How can I do?
    Thank you very much!

  8. Very good,

    Any clever types know how to add play on page scroll/position for the animations?

    It will save me very un-sociable weekend πŸ™‚

  9. Not bad but actually seem to really work in Chrome only. Even Firefox and IE11 (on Win8.1preview at least) on desktop do not work properly. I understand it is a proof of concept but I also guess a lot of people think this works at least on major desktop browsers (even if ignoring mobile) and will not bother to even check. I think a proof of concept for the web should at least work crossbrowser and not single browser only.

    All is not bad as the SVGs at least show: IE11 simple displays ’em without animation, Firefox is actually annoying as it flickers and seems to do the animation several times.
    So it kinda works but as said, for the web it is really an *experiment* and the article should clearly state that it should not be used on any website (yet). Would be nice to develop even experiments a little bit further…

  10. Hi, I’ve enjoyed many of your tutorials..but these really remind me of cheesy flash animations. The best out of all of them I think is the first “X” example…the others, I feel, aren’t subtle enough.

    Thanks for your great work though on all these cool examples.

  11. This is very cool… Exactly what I needed for a project of mine.

    But there is one problem with the script…. The SVG’s doesn’t work when you set some of the checkboxes to be pre-checked.

    Is there an easy way to fix this? πŸ™‚

  12. Thanks this is just what I was searching for. My recent project is now complete! After a few tweaks it works in other browsers besides Google Chrome.

  13. Great tutorial πŸ™‚ I wonder if somebody made it work with dynamically added elements.

  14. PreChecked FIX:
    Change svgcheckbx.js controlCheckbox() function to this:

    function controlCheckbox(el, type, svgDef) {
    var svg = createSVGEl(svgDef);
    el.parentNode.appendChild(svg);

    if (el.checked) { draw(el, type); }
    else {
    el.addEventListener(‘change’, function() {
    if (el.checked) {
    draw(el, type);
    } else {
    reset(el);
    }
    });
    }
    }

    • this will work:

      function controlCheckbox(el, type, svgDef) {
      var svg = createSVGEl(svgDef);
      el.parentNode.appendChild(svg);
      if (el.checked)
      {

      draw(el, type);

      }

      el.addEventListener(‘change’, function() {
      if (el.checked) {
      draw(el, type);
      } else {
      reset(el);
      }
      });

      }

    • This works for both Checkbox & Radio’s preChecked fix :

      function controlCheckbox(el, type, svgDef) {
      var svg = createSVGEl(svgDef);
      el.parentNode.appendChild(svg);
      if (el.checked) {
      draw(el, type);
      }
      el.addEventListener(‘change’, function() {
      if (el.checked) {
      draw(el, type);
      } else {
      reset(el);
      }
      });
      }

      function controlRadiobox( el, type ) {
      var svg = createSVGEl();
      el.parentNode.appendChild( svg );
      if (el.checked) {
      draw(el, type);
      }
      el.addEventListener( ‘change’, function() {
      resetRadio( el );
      draw( el, type );
      } );
      }

    • To change the color and the size of the checkmark go into component.css and on line 103 (stroke: #fdfcd3;) you can change the colour and on 104 (stroke-width: 13px;) you can change the width of the stroke. You can change the actual size of the mark by altering the width and height properties on lines 94 and 95.

  15. This is a really great little script, thanks so much for putting it all together!

    Just a note – I noticed that by default it only works when the required classes are applied to a form element, but I think it would be better to actually make it work with any possible html element. So I ended up removing the form part from the script and now I can apply the classes and use this animation in any element such as a div etc.

  16. Hi,
    Somehow I can reset the check box using jquery below but the SVG graphic does not go away. Text highlight is reset bu the radiobuttton is still decorated. Any idea how to fix this? Here is my code to reset.

    $(‘input[type=radio]’).prop(‘checked’, function () {
    return this.getAttribute(‘checked’) == ‘checked’;
    });

    Great tutorial.
    Mo

  17. I have the same question. How can I make checkmark already checked?
    does not work!

    HELP!

  18. Hi, thanks for the code snippet. In your warning that this feature may not work in mobile devices, do you mean to say that they will default to standard checkboxes, still functional just not as sexy, right?

  19. Hi,Mary!I really admire your work , and I want to port this demo to android.Could you provide a link to download the SVG images for this demo?(I have trouble to use the path data provide in the JS file. : ( Thx in advance.

  20. Hey, thanks a lot for this tutorial. It really helped, I was really struggling with checkboxes and CSS.

  21. This is amazing!

    but I am from Israel and I tried to use it but didn’t figure out how to modify it to be rtl compatible.

    can you please help?

    Thank you in advance. πŸ™‚

  22. Nice work! But I don’t see a way to mark a checkbox as checked? I’ve tried a couple of quick workarounds, but nothing solid. Perhaps you have a solution to this?
    Thanks!