Customising the appearance of checkboxes and radio buttons using CSS alone can be restrictive and challenging to maintain across different browsers and devices. However, by integrating custom graphics through labels, we can overcome these limitations.
The technique we’re going to discuss involves hiding the default input field and using a combination of CSS pseudo-elements and sibling selectors to create our own custom graphics.
First, let’s understand the structure of our HTML. We have an input field (either a checkbox or a radio button) and a label associated with it. The label is styled to look like a custom checkbox or radio button. In this example we are styling a Gravity Forms checkbox, but your markup might be a little different. Rest assured, as long as the input and label fields are set up within the same hierarchy, you can adapt this example to suit your needs.
<div class="gchoice">
<input class="gfield-choice-input" type="checkbox" id="choice1">
<label class="gform-field-label" for="choice1">Choice 1</label>
</div>
In the CSS, we first hide the actual input field using display: none;. This hides the default checkbox or radio button, but it doesn’t affect its functionality as we can still trigger the field by clicking its label instead.
.gchoice .gfield-choice-input {
display: none;
}
.gchoice .gform-field-label {
display: flex;
align-items: center;
padding: 10px;
cursor: pointer;
}
Next, we style the label to look like a custom checkbox or radio button. We use the ::before pseudo-element to create a box that will serve as our custom checkbox or radio button. We set its dimensions, background colour, and other properties to make it look the way we want.
.gchoice .gform-field-label::before {
content: " ";
display: block;
min-width: 25px;
width: 25px;
height: 25px;
background-color: #2f2f2f;
margin-right: 1rem;
}
Now comes the magic part. We use the :checked pseudo-class in combination with the sibling selector (+) to change the appearance of our custom checkbox or radio button when the label is clicked and the input field is checked. In this case, we change the background colour and add a background image (a checkmark SVG in this case).
.gchoice input:checked + .gform-field-label::before {
background-color: #95c11f;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath d='M0 0h24v24H0z' fill='none'/%3E%3Cpath d='M5 12l5 5L20 7' stroke='currentColor' stroke-width='2' fill='none'/%3E%3C/svg%3E");
background-repeat: no-repeat;
background-position: center;
background-size: 15px auto;
}
This way, even though the actual input field is hidden, we can still visually indicate its checked state using our custom CSS!