Skip to main content
Ben Nadel at cf.Objective() 2012 (Minneapolis, MN) with: Matt Graf and Nolan Erck
Ben Nadel at cf.Objective() 2012 (Minneapolis, MN) with: Matt Graf Nolan Erck

Using CSS Webkit-Appearance To Style Checkbox ::after Pseudo-Element

By
Published in Comments (9)

Last weekend, my mind was blown by Divya Sasidharan, who mentioned that you could use webkit-appearance to add custom CSS styling to native form elements. Since then, I've been on the lookout for examples of this; and, just yesterday, I came across a fascinating checkbox on the Coolors color-palette generator site. In their Settings panel, not only did they use -webkit-appearance:none to style their checkboxes, they were also using the ::after pseudo-element! Hold the phone! I had no idea that the checkbox even had pseudo-elements. As such, I had to try this technique out for myself.

Run this demo in my JavaScript Demos project on GitHub.

View this code in my JavaScript Demos project on GitHub.

The Coolors' checkboxes are styled to resemble a "switch toggle", much like you would see in an iOS application. The input element is the "track" of the toggle; and, the input::after is the "thumb". From what I've been Googling, most input elements don't support pseudo-elements; but, apparently, the type="checkbox" has good, though possibly undocumented, cross-browser support? My Google-fu is failing me on this matter.

Anyway, here's my attempt to recreate the custom CSS styling I've seen on Coolors checkbox:

<!doctype html>
<html lang="en">
<head>
	<meta charset="utf-8" />
	<meta name="viewport" content="width=device-width, initial-scale=1.0" />

	<title>
		Using CSS Webkit-Appearance To Style Checkbox ::after Pseudo-Element
	</title>
</head>
<body>

	<h1>
		Using CSS Webkit-Appearance To Style Checkbox ::after Pseudo-Element
	</h1>

	<style type="text/css">

		label {
			align-items: center ;
			cursor: pointer ;
			display: flex ;
		}

		label input {
			margin: 0px 0px 0px 10px ;
		}

		/*
			Only apply custom styles to browsers that are going to support them. This is
			important because even old browsers will apply SOME of these CSS properties;
			and, we don't want to create Frankenstein checkboxes.
		*/
		@supports ( appearance: none ) or ( -moz-appearance: none ) or ( -webkit-appearance: none ) {

			input.custom {
				appearance: none ;
					-moz-appearance: none ;
					-webkit-appearance: none ;
				border: 2px solid currentcolor ;
				border-radius: 52px 52px 52px 52px ;
				box-sizing: content-box ;
				color: #999999 ;
				height: 18px ;
				padding: 2px 2px 2px 2px ;
				transition-duration: 300ms ;
				transition-property: border-color, color ; /* Safari needed border-color. */
				transition-timing-function: ease ;
				width: 52px ;
			}

			input.custom:checked {
				color: #ff3366 ;
			}

			/*
				NOTE: The ::after pseudo-selector is being applied to the INPUT itself,
				not a parent element. I had no idea this even works! I can't find any
				documented support on this (just some StackOverflow threads).
			*/
			input.custom::after {
				background-color: currentcolor ;
				border-radius: 10px 10px 10px 10px ;
				content: "" ;
				display: block ;
				height: 18px ;
				transform: translateX( 0px ) ;
				transition: transform 300ms ease ;
				width: 24px ;
			}

			input.custom:checked::after {
				transform: translateX( 27px ) ;
			}

		}

	</style>

	<p>
		<label for="checkbox1">
			Default checkbox:
			<input id="checkbox1" type="checkbox" />
		</label>
	</p>

	<p>
		<label for="checkbox2">
			Webkit-Appearance checkbox:
			<input id="checkbox2" type="checkbox" class="custom" />
		</label>
	</p>

</body>
</html>

As you can see, I'm using the @supports directive to ensure we only apply the custom CSS to browsers that will fully support it. This way, we don't end up with a wonky-looking checkbox that has some of the custom CSS, but that doesn't deliver the expected user experience (UX).

Then, within the @supports block, I'm applying custom CSS to both the input checkbox and its ::after pseudo-element, styling both the checked and unchecked states. And, when we run this in the browser, we get the following output:

Form input checkbox being styled using CSS webkit-appearance and ::after pseudo-element.

Cool beans!! This works quite nicely on Chrome, Firefox, Safari, and Edge (for Mac). It even works swimingly on my Apple iPhone mobile Safari and mobile Chrome (which I think both use Webkit under the hood). And, of course, for browsers that don't support either the @supports block or the webkit-appearance, we just get the browser's native user-agent styling:

Form input checkbox default styles on IE11.

That's what's so exciting about this technique! It's minimal effort to add the custom CSS styling to the checkbox; and, it degrades quite gracefully! I am loving the world of progressive enhancement; and, finally releasing the archaic notion that every browser has to have pixel-perfect design. What an exciting time to be alive!

Want to use code from this post? Check out the license.

Reader Comments

15,848 Comments

@Karl,

I am not sure. I would guess there is, though :) People have been trying to style inputs since the dawn of time :D :D :D

15,848 Comments

@Charles,

Ha ha, oh man -- I think when I looked at your last CodePen, I saw the "Upload" and the "Select" and I think my brain totally skipped over what you were doing with the Radio buttons :D I think -- because I didn't even realize it was possible -- my brain didn't even fully register what you were doing.

Oh man, sorry about that! I didn't mean to disregard what you did - it was just more advanced than what my brain was ready to accept :P

448 Comments

Ben. No worries. I am always missing stuff. I think it has something to do with data overload. I just don't think our brains have had enough time to evolve, when it comes to technology. We are zapped from every angle with digital information.

Anyway, I am sure that there are clever CSS gurus, building customised form element libraries, as we speak!

After all, with:

-webkit-appearance: none;

The sky's the limit...

I believe in love. I believe in compassion. I believe in human rights. I believe that we can afford to give more of these gifts to the world around us because it costs us nothing to be decent and kind and understanding. And, I want you to know that when you land on this site, you are accepted for who you are, no matter how you identify, what truths you live, or whatever kind of goofy shit makes you feel alive! Rock on with your bad self!
Ben Nadel