Tuesday, May 28, 2024

Styling Radio Buttons and Checkboxes in HTML Forms

Build a Web Form with HTML – Part 5

In this series on Web Forms, we’ve been learning how to create and style various form controls. The last installment covered how to style labels and buttons, as well as how to alter an element’s appearance based on user interactions.

In today’s article, we’ll learn how to style a couple of notoriously challenging controls: radio buttons and checkboxes.

Before we move on, however, you may want to refresh your memory by revisiting the previous articles in this series:

General Strategy

The reason that I referred to radio buttons and checkboxes as being “notoriously challenging” in the intro is that they are both mostly unaffected by CSS styling. The usual attributes that you’d think would apply to radio buttons and checkboxes, such as border, color, and background-color, do nothing! Having said that, there are a few ways to circumvent these limitations to customize your radio buttons and checkboxes in a variety of eye-catching ways.

Right now, the most common strategy for customizing radio buttons and checkboxes is to:

  1. Hide the input element.
  2. Add an extra span element and apply your custom style by creating a class.

The rest of this article will walk through a few examples.

Styling Radio Buttons with CSS

Without CSS styling, radio buttons appear as a white circle with a black or blue dot when selected (depending on the browser):

Style Radio Buttons in CSS


This is the HTML markup that created the above form:

<h2>Styling Form Controls</h2>
<form id="register" name="register">
    <legend>Radio Buttons</legend>
      <p>Please select your favorite Pizza Topping:</p>
      <div class="divCSS">
        <input type="radio" id="pepperoni" name="toppings" value="pepperoni">
        <label for="pepperoni">Pepperoni</label>
        <input type="radio" id="mushrooms" name="toppings" value="mushrooms">
        <label for="mushrooms">Mushrooms</label>
        <input type="radio" id="other" name="toppings" value="other">
        <label for="other">Other</label>

Hiding the Input Element

The key to hiding the standard radio button is the appearance CSS property. It’s utilized to display an element using platform-native styling, based on the operating system’s theme. The -moz-appearance and -webkit-appearance properties are non-standard versions of this property, used respectively by Gecko (Firefox), WebKit-based (e.g., Safari) and Blink-based (e.g., Chrome, Opera) browsers to achieve the same thing. Setting the appearance to ‘none‘ removes the standard background appearance:

.divCSS > input[type="radio"] {
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
  /* ... */

Applying Custom Styles to Radio Buttons

With that done, we can proceed to style the radio buttons however we like. Here are the styles for unchecked radio buttons:

.divCSS > input[type="radio"] {
  /* remove standard background appearance... */

  /* create custom radio button appearance */
  display: inline-block;
  width: 15px;
  height: 15px;  
  padding: 3px;
  background-clip: content-box;
  border: 2px solid #060c3b;
  border-radius: 50%;
  margin-right: 0;

All that we need to add for checked radio buttons is the inner dot color:

.divCSS > input[type="radio"]:checked {
  background-color: blue;

Miscellaneous Styles for Radio Buttons using CSS

You’ll often find that, when you customize the appearance of form controls, you may want to tailor the look of the label text as well. The following CSS sets the font styles for the container and adds a margin to the right of the label to help space out the radio buttons:

.divCSS {
  font-family: Arial, Helvetica, sans-serif;
  color: #060c3b;
  font-weight: 500;

.divCSS > label {
  margin-right: 4px;

Here are the new-and-improved radio buttons as produced by all of the above styling:

Custom Radio Button Styling in CSS


Radio Button Interactions

Once you replace the standard radio buttons with your own, there is nothing stopping you from triggering style changes based on user actions such as focusing on or hovering over a radio button. Here’s some CSS that adds inner shading on hover and an outline on focus:

.divCSS > input[type='radio']:hover {
    box-shadow: 0 0 5px 0px blue inset;

.divCSS > input[type='radio']:focus {
   outline: 1px solid green;

You can see each of the states below:

CSS hover radio button styling
CSS Radio Button focus styling
Hover with Focus
CSS Hover and Focus Radio Button Interaction Example

Styling Checkboxes in CSS

One notable distinction between styling checkboxes and radio buttons is that, in the case of the former, we can also play with the HTML checkmark symbol (✓) to get it to look just right. By default, checkboxes have a gray border. When checked, the background color changes, and a checkmark appears inside the box:

CSS Checkboxes Example


Let’s duplicate the pizza toppings fieldset above so that the user can now select multiple items:

    <p>Please select your favorite Pizza Toppings:</p>
    <div class="divCheckboxes">
      <label class="checkbox">
        <input type="checkbox" />
      <label class="checkbox">
        <input type="checkbox" />
      <label class="checkbox">
        <input type="checkbox" />

Applying Default Styles to Checkboxes

Once again, we can use the CSS appearance property to remove all the native styling before applying our own styles:

.checkbox {
    display: inline-flex;
    cursor: pointer;
    position: relative;

.checkbox > span {
    color: #34495E;
    padding: 0.25rem 0.25rem;

.checkbox > input {
    height: 20px;
    width: 20px;
    -webkit-appearance: none;
    -moz-appearance: none;
    appearance: none;
    border: 1px solid #34495E;
    border-radius: 4px;
    outline: none;
    transition-duration: 0.3s;
    transition-property: all;
    background-color: teal;
    cursor: pointer;

Most of the attributes above probably look familiar to you by now, with the exception of the two transition ones. When combined with a transition-property of “all“, transition-duration will animate all properties that can transition between this selector and those which override it, such as the ones we’ll add for the checked state.

Altering the checked State

The check state is of course selected using the :checked pseudo-class. Here are the rules that employ it to target checked inputs:

.checkbox > input:checked {
    border: 1px solid #41B883;
    background-color: #34495E;

.checkbox > input:checked + span::before {
    content: '\2713';
    display: block;
    text-align: center;
    color: #41B883;
    position: absolute;
    left: 0.5rem;
    top: 0.2rem;

.checkbox > input:active {
    border: 2px solid #34495E;

Of these rules, the middle one is of particular interest; it’s the one that styles the checkmark. The ‘\2713‘ context is CSS code for the checkmark symbol. We can also set its position, color, and size.

Here are the resulting checkboxes in action:

Custom Checkboxes in CSS


You’ll find the demo for this tutorial on jsfiddle.net.

Conclusion to CSS Radio Button and Checkbox Styling

Previously, the only way to override the default appearance of HTML radio buttons and checkboxes was to hide it and employ SVG images and JavaScript code. Now, thanks to The CSS appearance property and HTML checkmark symbol, we can achieve the same result using pure CSS.

In the next installment, we’ll learn how to style HTML Selects.

Rob Gravelle
Rob Gravelle
Rob Gravelle resides in Ottawa, Canada, and has been an IT guru for over 20 years. In that time, Rob has built systems for intelligence-related organizations such as Canada Border Services and various commercial businesses. In his spare time, Rob has become an accomplished music artist with several CDs and digital releases to his credit.

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Popular Articles