Skip to main content
Ben Nadel
On User Experience (UX) Design, JavaScript, ColdFusion, Node.js, Life, and Love.

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

By Ben Nadel on
Tags: HTML / CSS

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!


Reader 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

Reply to this Comment

@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

Reply to this Comment

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

Reply to this Comment

Post A Comment

You — Get Out Of My Dreams, Get Into My Blog
Live in the Now
Oops!
NEW: Some basic markdown formatting is now supported: bold, italic, blockquotes, lists, fenced code-blocks. Read more about markdown syntax »
Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.