Cosmetic improvements to checkboxes and radios using CSS
Radios (or radio buttons) and checkboxes are very important input elements commonly found in so many forms on the web.
Checkboxes are used where multiple values from a list of predefined values may apply — for example, marking multiple files for deletion from a list of files.
Radio buttons on the other hand are used where only one value is applicable — for example, selecting gender from a list.
In this tutorial, we’ll examine using a step-by-step approach, how to improve the aesthetics and appearance of radios and checkboxes using CSS while still preserving the accessibility of the input elements.
In order to fully appreciate this tutorial, a basic understanding of CSS — selectors and style rules is required. However, you don’t really have to be a CSS expert to follow through.
When it comes to appearances, radios and checkboxes are somewhat awkward and inconsistent across different browsers. Often times, a uniform appearance is desired for checkboxes and radio buttons, irrespective of the browser being used.
Most CSS frameworks like Bootstrap already provide custom styling for the appearance of these input elements. However, if you are not using a CSS framework, you may need to be able to customize your own checkboxes and radio buttons — hence this tutorial.
Here is an outline of steps to follow in order to create a customized radio button or checkbox. In this list, I will keep referring to a checkbox or radio button as just input element.
- Ensure you have a label for the input element.
Wrap the input element with a
<label></label>element and attach a label text for the input element if necessary. This is also useful for maintaining the accessibility of the input element.
- Add the customization element after the input element.
The customization element is an empty element that will hold all the styles for the custom appearance of the input. It must come after the input element and they must both have the same parent element.
- Make the native input element go away.
Add the necessary styles to prevent the native input element from being visually presented. Avoid using styles that will remove the input element from the visual flow of the page, since they will be ignored by screen readers and will also impact keyboard accessibility negatively.
- Customize all you want.
Add the necessary styles to the customization element to get the desired custom appearance of the input. Use the
:checkedpseudo-class to add styles based on the checked state of the input element.CSS generated content may be used if necessary, leveraging on
We will go ahead and implement our customizations based on the design blueprints we’ve just seen. We’ll start with a minimalistic markup for the custom input element and then the styles.
Here is a sample markup HTML for the input element.
The checkbox element here is defined with a
check-custom class. The customization element for the checkbox is given a class of
Using classes in this way makes it easy to opt in or out of the customization. For example — if the
check-custom class is not passed, the native checkbox is shown instead.
Hide the Native Element
You could easily attach the
hidden attribute to the input element to prevent it from being visually presented like so:
<input type="checkbox" class="check-custom" hidden>
However, this should be discouraged. CSS styles should be used to hide the native input element instead.
Here is a simple style definition to ensure that the native input element is not visually presented.
Here, an attribute selector and a
.check-custom class selector are used with the
input type selector to ensure that the styles apply to only checkboxes with the specified class.
Customize the Checkbox
First, we will add the basic styles for the appearance of the checkbox as follows:
Notice how the general sibling combinator (
A ~ B) was used in the selector to target the customization element after the input element. Here it is again:
input[type='checkbox'].check-custom ~ .check-toggle
This selector will match any element with a
check-toggle class, that is a direct sibling of and comes after any checkbox
input element with a
Finally, it’s time to add styles for the various states of the check box.
Notice here that I have used an inline SVG of a white checkmark in addition to a blue derivative color as the background for the custom checkbox when it is checked.
Though I have used very simple styles here, it is completely up to you to use as much styling as will be required for the customization you desire.
Here are the complete styles for the custom checkbox:
Here is a very simple demo, comparing the appearances of the custom and native checkboxes. (Additional styles have been applied to aid the visual presentation)
Implementing Custom Radio Button
We’ve already seen an implementation for a custom checkbox. Let’s quickly see how we can implement a custom radio button by following the design blueprint we saw earlier.
Here is a sample markup HTML for the radio button.
Here, we have changed the input type to
radio. We have also retained the class names on the elements for consistency.
Before we go on to writing the styles for our custom radio button, let’s have a fair idea of what our radio button should look like.
Here is a side-by-side comparison between the appearance of our custom radio button and the native one.
Styling the Radio Button
From the screenshot above, it can be seen that our custom radio button has something that looks like a small box at its middle when it is in checked state.
To create that box for the checked state, we will leverage on the
::after pseudo-element of the customization element.
All other styles are almost the same with what we saw before for the checkbox. Here are the styles needed to create our custom radio button.
Notice here that we are now using the
input[type=’radio’] base selector to ensure that we are targeting only radio buttons. Remember again that it’s completely up to you to style the custom radio button however you seem fit.
Case Study: Toggle Switch
There are a couple of use cases for customized checkboxes and radio buttons that may not be so apparent. One of these is the toggle switch.
A toggle switch can be seen as a checkbox that toggles between two values based on its checked and unchecked state — usually having the appearance of a switch.
We can modify the styles for the customization element of our custom checkbox to give it the appearance of a switch.
Let’s start with a sleight modification of the markup to add a
toggle-switch class to the input element. Here is what it is:
Checkbox — Why not Radio?
Notice, in the markup for the toggle switch, that we are using an input type of
checkbox for the toggle switch. A good question will be — “Can we also use a
radio input element?”
The answer is NO. The reason is due to the difference in the toggle behavior of a radio button and a checkbox when they are already in checked state.
A radio button on its own cannot be unchecked by mere user interaction when already in checked state. Hence, it is not ideal for use as a toggle switch.
This simple demo shows the difference between using a radio button and a checkbox as the basis for a toggle switch.
We will make a couple of modifications to the styles for the customization element to make it look like a switch.
A typical switch consists of an outer frame and an inner slider that aligns to either the left or right side of the frame depending on the state of the switch.
To achieve this design, we will leverage on the
::after pseudo-elements of the customization element. The
::before pseudo-element will be the outer frame, while the
::after pseudo-element will be the inner slider.
The resulting toggle switch will look like the following screenshot — (Additional styles have been applied to aid the visual presentation)
Here are the styles for the toggle switch:
For all the customizations we did in this tutorial, we were able to ensure that our custom radio buttons and checkboxes remained accessible — which is a very good feat by the way.
Hence, tab focusing, check toggling with spacebar and all other accessibility characteristics of the input elements are preserved. This is possible because:
<label></label>element was used to wrap the input elements. Hence always remember to wrap the native input element and the customization element in a parent
- the native input elements are still preserved in the visual flow of the page, even though they are not visually presented.
Another important improvement on the accessibility of our customized elements will be to add a text or element that provides a readable label — using any of the following options:
- a child element or text within the parent
- a hidden label text specified using the
- a separate element linked to the input element using the
Still on ARIA attributes, you can also use the
aria-checked attribute together with the basic
checked to indicate checked state of the input elements.
For the toggle switch, you should add the ARIA role
role=”switch” to the input element to indicate that it is a toggle switch.
Finally, always ensure that you employ adequate styles for the
focus state of the input element in order to provide a useful visual cue.
Finally, we’ve come to the end of this tutorial and we’ve seen a very simple design blueprint that can guide us in making cosmetic changes to native radio buttons and checkboxes with just CSS, and still preserving their accessibility.
Like stated in the tutorial, you are not restricted to the customization styles used in the tutorial. In fact, it’s completely up to you to style the custom elements however you seem fit.
Clap & Follow
If you found this article insightful, feel free to give some rounds of applause if you don’t mind.