Default radio buttons and checkboxes don’t always match your website’s design. In this tutorial, you’ll learn how to fully customize them using HTML, CSS and your own check icon or symbol.
We’ll hide the native input and style the visual version however we like — all accessible and beginner-friendly.
👁️ Preview
🧱 Step 1: Create the Basic HTML Structure
We’ll start with two checkboxes and two radio buttons.
<h2>Custom Checkbox</h2>
<label class="custom-checkbox">
<input type="checkbox" />
<span class="checkmark">✔</span>
Subscribe to newsletter
</label>
<h2>Custom Radio</h2>
<label class="custom-radio">
<input type="radio" name="plan" />
<span class="dot">●</span>
Free Plan
</label>
<label class="custom-radio">
<input type="radio" name="plan" />
<span class="dot">●</span>
Pro Plan
</label>
✅ Explanation
- We use a
<label>
so clicking the text also triggers the input. - The
input
is visually hidden but still functional. - The
span
acts as the visual icon (which we can style freely).
🎨 Step 2: Style with CSS to Hide the Default Inputs
input[type="checkbox"],
input[type="radio"] {
display: none;
}
/* Common label styling */
label {
display: flex;
align-items: center;
margin: 10px 0;
font-family: Arial, sans-serif;
cursor: pointer;
}
/* Checkmark box */
.custom-checkbox .checkmark {
width: 20px;
height: 20px;
border: 2px solid #7179F4;
display: inline-flex;
align-items: center;
justify-content: center;
margin-right: 10px;
font-size: 14px;
color: white;
background-color: transparent;
transition: all 0.3s ease;
}
/* Dot circle */
.custom-radio .dot {
width: 20px;
height: 20px;
border: 2px solid #7179F4;
border-radius: 50%;
display: inline-flex;
align-items: center;
justify-content: center;
margin-right: 10px;
font-size: 12px;
color: white;
background-color: transparent;
transition: all 0.3s ease;
}
/* When checked, fill the icon */
input[type="checkbox"]:checked + .checkmark {
background-color: #7179F4;
}
input[type="radio"]:checked + .dot {
background-color: #7179F4;
color: white;
}
🧠 How It Works
- We hide the real input with
display: none
. - We use the adjacent selector
+
to apply styles to the custom span when the input is:checked
. - The content of the
span
(✔
or●
) can be replaced by any icon, symbol, SVG, or even background image.
🧩 Optional: Use Your Own Icon or Image
Instead of using a text symbol, you can use an image:
<span class="checkmark">
<img src="check-icon.svg" alt="" />
</span>
And in CSS:
.custom-checkbox .checkmark img {
width: 16px;
height: 16px;
}
✅ Final Result
You now have beautiful, accessible, and fully customizable:
- ✅ Checkboxes
- ✅ Radio buttons
All styled with your own icons or symbols and responsive to user interaction.
🧩 Bonus Tips
- Add
:focus
styles for accessibility. - Use
aria-checked
or properrole="checkbox"
if building from scratch (not needed here since we use real inputs). - Icons can come from icon libraries like Phosphor, Font Awesome, etc.