So you want to style checkboxes and radio buttons to look more awesome than the default styling? Well, you are in the right place. These input values are a bit of a pain, and the default options tend to look a lot different depending on which browser you are using. There are several ways to do this, but today we will show you a great solution that focuses on accessibility.
Let’s get cracking! In this tutorial we will be using the following:
- ::before and ::after pseudo-elements
- :checked CSS pseudo-class selector
- + adjacent sibling selector
The great thing about using these techniques is that almost all browsers (IE 10 and above) have great support for this.
We are going to demonstrate how to do these using checkboxes, radio buttons use the same approach, just with slightly different styles; nail one, you got them both!
So firstly, let’s make your HTML markup like below:
<div class="checkbox">
<input type="checkbox" id="my-checkbox">
<label for="my-checkbox">CSS Only Checkbox</label>
</div>
What we have done here is wrap the input
and label
elements with a div called checkbox
so that we know this part of code represents a checkbox.
For this to work in the way we will be demonstrating, the following things are required: (otherwise tweaks will be required based on your HTML markup)
- The
label
must appear after the<input type="checkbox">
- The
id
attribute is required on the<input type="checkbox">
- The
for
attribute is required on thelabel
Now for the CSS, we are going to show this in steps, if you just want the full code; click here.
Step 1.
Since we can’t style the default checkbox using CSS, we are going to hide it. There are several ways to do this but we are going to hide it using opacity: 0
as follows:
.checkbox input[type="checkbox"] {
opacity: 0;
}
Step 2.
Now we are going to create a ‘fake’ checkbox using pseudo-elements, this will be done by using the ::before
and ::after
pseudo elements.
We will use the ::before
to create the outer box and ::after
to create the checkmark.
Both of these elements will be positioned before the text in the label.
Let’s start by creating the outer box. What we will do here is make the ::before
pseudo-element and inline-block and assign an equal width and height. We will add a border to make it visible. Depending on the way you wish to style it, this will look like this:
.checkbox label::before{
content: ' ';
display: inline-block;
height: 16px;
width: 16px;
border: 1px solid #000;
}
Now, let’s create the checkmark using the ::after
pseudo-element. We are going to set this as an inline-block element and assign it height and width. We’ll also add custom styles to its left and bottom borders and rotate it by 45 degrees to make it appear like a checkmark.
.checkbox label::after {
content: ' ';
display: inline-block;
height: 6px;
width: 9px;
border-left: 2px solid;
border-bottom: 2px solid;
transform: rotate(-45deg);
}
In this next part, we will be aligning the outer box and checkmark. We will be using absolute
positioning to position both pseudo-elements relative to the text in the label like so:
.checkbox label {
position: relative;
}
.checkbox label::before,
.checkbox label::after {
position: absolute;
}
.checkbox label::before {
top: 3px;
}
.checkbox label::after {
left: 4px;
top: 7px;
}
Step 3.
Now, we are getting very close. We just need to create a way for the checkmark to appear/disappear based on the state of the checkbox.
You may have noticed that there is an ID for the <input type="checkbox">
and also for the attribute on the label. It’s possible to toggle the state of the default checkbox by clicking the label. The reason we placed the label after the <input type="checkbox">
is so that we can change the state using the adjacent (+) sibling selector as shown below:
/* Hide Checkmark */
.checkbox input[type="checkbox"] + label::after {
content: none;
}
/* Show Checkmark on Checked State */
.checkbox input[type="checkbox"]:checked + label::after {
content: "";
}
Step 4.
Now we have a working, custom styled checkbox. If you want to take this one step further and make it accessible, then keep reading!
We will use the :focus
selector on the <input type="checkbox">
, we can again use the adjacent (+) sibling selector to give the ::before
pseudo-element (outer box) of the label a focus style. To do this, we can add the following code:
.checkbox input[type="checkbox"]:focus + label::before {
outline: rgb(59, 153, 252) auto 5px;
}
And there we have it, folks, we now have a fully accessible, customisable and functional checkbox in just four simple steps.
Awesome right?
To Conclude
To create a custom checkbox using pure CSS your code will look as follows:
HTML
<div class="checkbox">
<input type="checkbox" id="my-checkbox">
<label for="my-checkbox">CSS Only Checkbox</label>
</div>
CSS
body {
font-size: 20px;
line-height: 24px;
}
.checkbox input[type="checkbox"] {
opacity: 0;
}
.checkbox label {
position: relative;
display: inline-block;
padding-left: 30px;
}
.checkbox label::before,
.checkbox label::after {
position: absolute;
content: ' ';
display: inline-block;
}
.checkbox label::before {
height: 16px;
width: 16px;
border: 1px solid #000;
left: 0px;
top: 3px;
}
.checkbox label::after {
height: 5px;
width: 9px;
border-left: 2px solid;
border-bottom: 2px solid;
transform: rotate(-45deg);
left: 4px;
top: 7px;
}
.checkbox input[type="checkbox"] + label::after {
content: none;
}
.checkbox input[type="checkbox"]:checked + label::after {
content: ' ';
}
.checkbox input[type="checkbox"]:focus + label::before {
outline: rgb(59, 153, 252) auto 5px;
}
You can view a demo of this here on CodePen.
We hope you loved this tutorial, if it has helped you or if you require any assistance with anything, feel free to drop us a comment below.