how to create custom radio button in reactjs

The Most Efficient Way to Create a Custom Radio Button in ReactJS

Author Profile
Abdul Basit OnLinkedIn

A key component of forms in any website is a radio button. We use them when a user is required to choose just one option from a list. The game changes when you customize the default Radio Button in ReactJS and give it personal look.

Sometimes we are given a design of a Radio button that is different from the default one. So we have to build a custom radio button to mimic the design.

You’ll master the fundamentals and how to create a unique radio button in reactjs in this article.

Before starting, let me show you how our ultimate result will look.

radio button result

Custom Radio Button React Codepen

If you just want the code, it's right there in the Codepen widget. But if you prefer to understand how it's made, check out the article for a step-by-step guide.

Difference between Radio button and Checkbox

Before starting I would like to describe where to use the radio buttons and where to use the checkboxes so a beginner should not get confused.

A radio button is used for selecting only one option from a list while a checkbox is used for selecting multiple options.

Radio button is perfect for choices like gender and civil status since a user can only have one.

Default Radio Button UI

We all know creating a default Radio button in react js is pretty easy.

function RadioButton() {
const onChange = (e) => {
const { name } = e.target
console.log('clicked', name)
}
return (
<label htmlFor="dark">
<input type="radio" name="dark" id="dark" value="dark" onChange={onChange} checked={true} />
Dark
</label>
)
}

This is how the default radio button UI looks like in Reactjs.

react default radio button

Custom Radion Button in Reactjs

For custom radio button we will be using a trick, the trick will be quite simple and straightforward.

Since we have limited options available and can not play much with the default Radio button CSS (UI) so we are going to hide it using CSS.

const RadioButton = () => {
const onChange = (e) => {
const { name } = e.target
console.log('clicked ==>', name)
}
return (
<label htmlFor="dark" className="radio-label">
<input
className="radio-input"
type="radio"
name="dark"
id="dark"
value="dark"
onChange={onChange}
checked={false}
/>
Dark
</label>
)
}

Here we have added a radio-input class and styled it using CSS.

Hiding the Default Radio Button CSS Properties

.radio-label {
}
.radio-input {
visibility: hidden;
}

Key Point

You may notice we made visibility: hidden property but not display: none.

Do you have any idea why?

Because in case of display none, the element doesn't exist in DOM and we can not use any of input:radio prop, while visibility hidden just hides the UI, we can still use it props.

In short, we are interested in its props and onChange function but not the UI.

Adding a Radio button onChange function

const onChange = (e) => {
const { name } = e.target
console.log('clicked ==>', name)
}

Since radio button is an input element so its onChange function works the same way it works for other input types like text, email, password, etc. We have passed a name prop in input tag, so we can get a name of the selected (targeted) input and take action accordingly.

The radio circle is hidden, but if we inspect the browser and click the label we can see the console dark, it means our onChange function is working and we are receiving the name of the targeted element..

hide radio ui broswer result

Remember

If radio button checked is true means it is already selected then onChange function will not work.

To create a custom radio circle, we added an empty span inside our radio button component. We will style this span like radio or custom design we are given as you have seen above. You understood my point. Right?

const RadioButton = ({ name, id, value, onChange, checked, text }) => {
return (
<label htmlFor={id} className="radio-label">
<input
className="radio-input"
type="radio"
name={name}
id={id}
value={value}
onChange={onChange}
checked={checked}
/>
<span className="custom-radio" />
{text}
</label>
)
}

In this step, we have also made Radio Button component reusable via props.

We are almost done with jsx part but before we switch to CSS let me explain why we added an id attribute to the label and input tag and what are the advantages of it.

Why use the id in Radio Button?

Adding an id is beneficial for user experience (UX). With an id, we can select by clicking on the text or even a radio circle. If we don’t add an id, the only way to choose the option is by clicking the radio button, not the circle text (label).

Styling Custom Radio Button

Understanding the CSS for custom radio button component in React is essential.

We have already talked about why we made visibility hidden of radio input component.

Now we need to talk about two more style optimization:

  1. Styling Radio circle
  2. Styling Radio circle when it is selected

1. Styling Radio Circle

We’ll start by discussing the style of custom radio circle we made.

As we have added span tag with the class of custom-radio to style it.

.custom-radio {
left: -8px;
top: 6px;
cursor: pointer;
width: 17px;
height: 17px;
border: 2px solid #9a9a9a;
border-radius: 50%;
display: inline-block;
position: relative;
}
/* for inner filled circle */
.custom-radio::after {
content: '';
width: 12px;
height: 12px;
background: #f4b400;
position: absolute;
border-radius: 50%;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
opacity: 0;
transition: opacity 0.2s;
}

2. Styling Radio Circle When It Is Selected

The last but not least concept is here, in this style we are saying, when radio button is checked(selected), add a border in radio input UI border: 2px solid #f4b400; and make the opacity of custom-radio class from 0 to 1.

We select the custom-radio::after pseudo-class using CSS adjacent selector.

Here you can read more about how to select CSS adjacent classes and other CSS sectors.

.radio-input {
visibility: hidden;
}
.radio-input:checked + span {
border: 2px solid #f4b400;
}
.radio-input:checked + span:after {
opacity: 1;
}

We are done with the component code and its style, let's test the component.

Let's say we are giving an option to user to select a theme either light or dark, for that we are using the radio button component we just made. This can be used for any purpose, like selecting gender, marital status, etc.

const App = () => {
const [theme, setTheme] = useState({ dark: false, light: false })
const onChangeTheme = (e) => {
const { name } = e.target
console.log('clicked', name)
if (name === 'light') {
setTheme({ dark: false, light: true })
}
if (name === 'dark') {
setTheme({ dark: true, light: false })
}
}
return (
<div className="select-theme">
<p>Please select a theme</p>
<RadioButton
name="dark"
id="dark"
value="Dark"
text="Dark"
onChange={onChangeTheme}
checked={theme.dark}
/>
<RadioButton
name="light"
id="light"
value="Light"
text="Light"
onChange={onChangeTheme}
checked={theme.light}
/>
</div>
)
}

First of all, we defined a state for options we want the user to select.

By default both options are unchecked or unselected, then on basis of user selection, we are changing the state and making that clicked option true using below function. You can change this function as per your need.

const onChangeTheme = (e) => {
const { name } = e.target
if (name === 'light') {
setTheme({ dark: false, light: true })
}
if (name === 'dark') {
setTheme({ dark: true, light: false })
}
}

Custom Radio Button Reactjs Complete Component

import React from 'react'
import './index.css'
const RadioButton = ({ name, id, value, onChange, checked, text }) => {
return (
<label htmlFor={id} className="radio-label">
<input
className="radio-input"
type="radio"
name={name}
id={id}
value={value}
onChange={onChange}
checked={checked}
/>
<span className="custom-radio" />
{text}
</label>
)
}
export default RadioButton

Radio Button CSS Code

@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500&display=swap');
body {
font-family: 'Poppins', sans-serif;
margin: 0;
padding: 0;
box-sizing: border-box;
display: flex;
justify-content: center;
}
.select-theme {
margin-top: 20px;
}
.select-theme p {
margin: 0 0 5px 0;
padding: 0;
}
.radio-label {
color: #303030;
font-size: 14px;
font-weight: 400;
margin-right: 7px;
-webkit-tap-highlight-color: transparent;
cursor: pointer;
}
.radio-input {
margin: 0;
visibility: hidden;
}
.radio-input:checked + span {
border: 2px solid #f4b400;
}
.radio-input:checked + span:after {
opacity: 1;
}
.custom-radio {
left: -8px;
top: 6px;
cursor: pointer;
width: 17px;
height: 17px;
border: 2px solid #9a9a9a;
border-radius: 50%;
display: inline-block;
position: relative;
}
/* for inner filled circle */
.custom-radio::after {
content: '';
width: 12px;
height: 12px;
background: #f4b400;
position: absolute;
border-radius: 50%;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
opacity: 0;
transition: opacity 0.2s;
}

Read More On This

Since a Radio Button is a part of a form element, it's good to know about ReactJS form best practices.

A form remains incomplete without an input element, so learn how to build a reusable input component in ReactJS with error.

Wait,

To submit the form, a Submit Button is needed. Read about how to build a loading spinner in ReactJS.

Summing Up

Radio Buttons are great when you want users to select one option. We have tried to explain how to create custom radio buttons, how to use onChange function, and basic hidden visibility technique. Don’t forget to implement it and use it in your own style.