How to style checkbox and radio buttons using CSS

Temani Afif

Web Developer ··Website Tips

How to style checkbox and radio buttons using CSS

We all agree that the default styles applied to input elements like checkbox and radio aren’t that good. They are also different between browsers. For this reason, we always tend to update the default styles to create our design. In this post, we will study CSS techniques that allow us to update the style of such elements without extra HTML code. Yes, we are going to give a fresh look to our <input> elements using only CSS!

In this post, I will focus on the CSS part so all the demos will include only the <input> elements for simplicity.

Radio buttons


Let’s start with a basic example:

As you can see in the demo, I am not adding any extra HTML code. Only a few lines of CSS are needed.

The first step is to disable the default browser styles using the following code:

input {
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
}

Now, we have a “naked” radio button that we can style as we want. What I am doing next is pretty simple. I am giving the checkbox a dimension, a border, and some padding:

input {
  width: 40px;
  height: 40px;
  border: 5px solid grey;
  padding: 5px;
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
  cursor:pointer;   /* don't forget this as well */
}

Then, I am using the :checked pseudo-class to update the style when the element is checked

input:checked {
  background: green content-box;
  border-color: green;
}

I am adding a background that will cover only the content area (thanks to content-box) leaving a gap with the border. I am also giving the border a green color. That’s all!

This basic example illustrates how we can style a radio element without using any extra element. Of course, we will not stop there. We are going to add more CSS to have a better design.

Let’s update the previous example by introducing some CSS variables and transitions:

input {
  --s: 40px;
  
  width: var(--s);
  aspect-ratio: 1; /* OR height: var(--s) for old browsers */
  border: calc(var(--s)/8) solid var(--_c,grey);
  padding: calc(var(--s)/8);
  background: var(--_c,#0000) content-box;
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
  cursor: pointer;
  transition: .3s;
}
input:checked {
  --_c: green;
}

Instead of setting each property individually, I define one variable (--s) that I use to set the dimension, padding, border, etc. By only adjusting that variable, we can easily control the overall size.

I am doing the same with the coloration. Since the border and background need to be green on checked, I am defining one variable for that purpose.

Let’s consider a more fancy animation

Things start to get more funny! Instead of simply changing the colors, we are having a size animation of the inner part.

To do this, I am using a gradient instead of background color and I am changing the background-size on :checked

input {
  --s: 40px;
  --c: green;
  
  width: var(--s);
  aspect-ratio: 1;
  border: calc(var(--s)/8) solid var(--_c,grey);
  padding: calc(var(--s)/8);
  background: linear-gradient(var(--c) 0 0) 50%/0 0 no-repeat content-box;
  transition:.3s;
}
input:checked {
  --_c: var(--c);
  background-size: 100% 100%;
}

Notice the usage of another variable that allows me to control the color as well.

For the rounded radio button, we need a radial-gradient instead of a linear one

.round {
  border-radius: 50%;
  background: radial-gradient(farthest-side,var(--c) 96%,#0000 ) 50%/0 0 no-repeat content-box;
}

Let’s add an effect to the border:

In addition to the gradient, I am using an outline:

input {
  --s: 40px;
  --c: green;
  
  border: calc(var(--s)/8) solid grey;
  outline: calc(var(--s)/8) solid var(--_c,#0000);
  outline-offset: calc(var(--s)/4);
}
input:checked {
  --_c: var(--c);
  background-size: 100% 100%;
  outline-offset: calc(var(--s)/-8);
  border-color: #0000
}

I am defining an outline equal to the border width. Initially, the outline color is transparent and the offset is a positive value expressed with the variable --s. On :checked, I change the color of the outline, I make the offset negative to create an overlap with the border and I change the color of the border to transparent.

We have a cool radio button with only CSS a stated in the introduction. Not only this, but we can easily adjust things using CSS variables.

Below two more examples to show a full code including custom radio buttons

Checkbox


Styling a checkbox is the same as styling a radio button. The only difference between both is their functional part which is out of the scope of this post.

For this one, I will focus on my favorite design which is the toggle (also called switch)

input {
  --s:40px;
  
  height: var(--s);
  padding: calc(var(--s)/10);
  box-sizing: content-box;
  aspect-ratio: 2;
  border-radius: var(--s);
  background:
    radial-gradient(farthest-side,#fff 97%,#0000) 
     left/var(--s) 100% content-box no-repeat,
    grey;
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
  cursor: pointer;
  transition: .3s;
}
input:checked {
  background-position: right;
  background-color: green;
}

Like all the previous examples, we are going to use a CSS variable to control the size and then a gradient for the main trick.

At first glance, it may look difficult but the trick is pretty simple. We use a radial-gradient to create a circle placed on the left side within the content area (thanks to content-box). The padding will define the gap between the circle and the edge. On :checked we update the position to the right which will create the sliding effect thanks to the transition. As simple as that!

Let’s not forget about changing the background-color to green or whatever color you want to show the checked state.

Let’s consider another idea of a checkbox

input {
  --s:80px; /* adjust this to control the size*/
  
  height: var(--s);
  aspect-ratio: 2;
  padding: calc(var(--s)/5);
  border-radius: var(--s);
  background:
    radial-gradient(farthest-side,#fafafa 85%,#0005,#0000) left/var(--s) 100% no-repeat,
    linear-gradient(90deg,#20b68f 50%,#939393 0) right/200% 100% content-box;
  transition: 0.5s;
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
  cursor: pointer;
}
input:checked {
  background-position: right,left;
}

For this one, we are going to rely on two gradients. Like the previous one, a radial-gradient will create the circle. For the main background, we will consider a linear-gradient.

Below is an illustration to see how the bottom gradient behaves.

The linear-gradient has a width equal to twice the element width (the 200%) defined with two colors (the grey and green one) then we slide it from left to right as we do with the circle. Since it’s a background, we won’t see its overflowing part.

As you can see, using the same technique (background and gradients) we made 2 different checkbox using only the input element. And this is only a small overview of the possibilities. We can push the limit of CSS and create more fancy checkbox.

Here are a few more examples I recently made:

Conclusion


Thanks to modern CSS techniques we no more need to rely on hacks or a ton of HTML code to create fancy checkbox and radio buttons. All that is needed is the native input element and our creativity to get almost any design we want.

Frequently Asked Questions


Can you migrate my existing website over?

Yes, and without issue. Regardless of how many websites you’re managing, we’ll bring all of them under the Verpex wing free of charge. Just send us the details of your websites when you’ve signed up to get started.

How do I choose a design for my website?

One of the most important things when creating a website for your art is the design. Even though your pieces of art might be amazing, people will leave if your site is hard to navigate. This is why it’s important that the site is easy on the eyes and easy to navigate.

What are the hosting options with a website builder?

Most website builders offer a free plan with a free domain, but your name will go after the company's name. To get any address you like, you will need to purchase the domain name on your own.

How much does it cost to create a restaurant website?

For an essential restaurant website, it will cost you from $3000 to $10,000 on average if you hire a web design agency. However, if you decide to use a CMS and build it yourself, the cost will be much lower.

Temani Afif
About the Author
Temani Afif

Temani Afif is an expert web developer, a content creator, and a CSS addict. He is the mastermind behind css-challenges.com, css-generators.com, css-only.art, css-articles.com, and a lot of CSS stuff. He's also an active contributor at Stack Overflow answering all kinds of CSS questions.

View all posts by Temani Afif
Discount

Enter Discount Code MOVEME During The SIGN UP Process To Get 90% Off Your First Month

with the discount code

MOVEME

Use Code Now
Jivo Live Chat