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.
Animated Checkboxes

From our sponsor: Try Mailchimp today.

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>
		<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>

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:

The classic check mark for checkboxes:

A fill drawing for a radio button:

The filler text in the demo is from Corporate Ipsum.

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

Tagged with:

Mary Lou

ML is a freelance web designer and developer with a passion for interaction design. She studied Cognitive Science and Computational Logic and has a weakness for the smell of freshly ground peppercorns.

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

    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;