We have all been there staring at the same five or more radio buttons with same value or worse no value.
All we want is each radio button to have their own state value. The confusion lies at the heart of the DOM value vs the DOM element
Intro
I am going to code five radio buttons and show the underpinnings of react and how to handle multiple buttons in a single piece of state
Short version:
- The value of an element is a primitive data type:boolean, number etc
- The element is the actual node like html tag, className, id etc
- Event handler will make the connection to the state
Getting started
npx create-react-app radio-buttons
See the screenshot for the folder structure and code. I cleaned up the boilerplate and added useState
go here for the repo.
App.js
const App = () => {
return (
<div className='App'>
<h1>Radio Journey</h1>
</div>
);
};
export default App;
Index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
Index.css
Style for style points on your own or see mine later in the demo Styles
Ok now that we have the basic set up lets code through it.
We need to add state
and a radio button such as
import { useState } from 'react';
const App = () => {
//STATE
const [isRadio, setIsRadio] = useState(5);
return (
<div className='App'>
<h1>Radio Journey</h1>
<ul>
<li>
<input />
<label>1</label>
</li>
</ul>
</div>
);
};
export default App;
Next the <input/>
and <label/>
need a few props like so
import { useState } from 'react';
const App = () => {
//STATE
const [isRadio, setIsRadio] = useState(5);
return (
<div className='App'>
<h1>Radio Journey</h1>
<ul>
<li>
<input
type='radio'
id='radio1'
value='1'
onChange={handleChange}
checked={isRadio === 1}
/>
<label htmlFor='num1'>1</label>
</li>
</ul>
</div>
);
};
Styles
add style to get a visual interface of whats going on. Add this to your index.css
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: 'Courier New', Courier, monospace;
background-color: #090c57cb;
color: #fff;
line-height: 1.8;
}
ul {
list-style: none;
}
h1 {
text-align: center;
}
.container {
max-width: 768px;
margin: auto;
padding: 0 20px;
}
input {
flex-grow: 2;
border: none;
font-size: 16px;
}
input:focus {
outline: none;
}
.radios {
display: flex;
align-items: center;
justify-content: space-around;
margin: 30px 0 40px;
}
.radios li {
position: relative;
background: #f4f4f4;
width: 50px;
height: 50px;
padding: 10px;
text-align: center;
border-radius: 50%;
font-size: 19px;
border: 1px #eee solid;
transition: 0.3s;
}
li label {
position: absolute;
top: 110%;
left: 0;
width: 50px;
height: 50px;
padding: 10px;
border-radius: 50%;
}
.radios li:hover {
background: #f00303;
color: #fff;
}
[type='radio'] {
opacity: 0;
}
[type='radio']:checked ~ label {
background: #f00303;
color: #fff;
}
Should look like this
The <input/>
has everything it needs and we have styles. Next address the handleChange
and add four more radio buttons.
import { useState } from 'react';
const App = () => {
//STATE
const [isRadio, setIsRadio] = useState(5);
// HANDLE THE ONCHANGE HERE
const handleChange = (e) => {
// string passed in
// a string returned by default
console.log(e.currentTarget.value);
// add + to the event to make the value a number
setIsRadio(+e.currentTarget.value);
};
return (
<div className='App'>
<h1>Radio Journey</h1>
<ul className='radios'>
<li>
<input
type='radio'
id='radio1'
value='1'
onChange={handleChange}
checked={isRadio === 1}
/>
<label htmlFor='num1'>1</label>
</li>
<li>
<input
type='radio'
id='radio2'
value='2'
onChange={handleChange}
checked={isRadio === 2}
/>
<label htmlFor='num2'>2</label>
</li>
<li>
<input
type='radio'
id='radio3'
value='3'
onChange={handleChange}
checked={isRadio === 3}
/>
<label htmlFor='num3'>3</label>
</li>
<li>
<input
type='radio'
id='radio4'
value='4'
onChange={handleChange}
checked={isRadio === 4}
/>
<label htmlFor='num4'>4</label>
</li>
<li>
<input
type='radio'
id='radio5'
value='5'
onChange={handleChange}
checked={isRadio === 5}
/>
<label htmlFor='num5'>5</label>
</li>
</ul>
You should have this in your browser:
Notice the console.log(e.currentTarget.value)
Here is definition of the currentTarget Docs here:
"The currentTarget read-only property of the Event interface identifies the current target for the event, as the event traverses the DOM."
Let's run back through it. We have five radio buttons each one has a string value captured by the handleChange function when clicked. The string value needs to be changed to a number by adding the '+' sign in front of the e like so setIsRadio(+e.currentTarget.value);
Now that the clicked value is a number it gets updated to the state and isRadio
is a new value. The checked
prop is a unique identifier for the state to match to 'Hey checked your number value matches let's make you the star of the show'.
click event > handleChange > updates state > checked made it to the show.
Like always confirm with dev tools:
Conclusion
In this demo my intent was to show how to effectively utilize one piece of state with hooks and multiple radio buttons in code. The console and dev tools confirmed the UI is matching the state changes. I hope this demo was helpful. This demo is could easily be used to create your next radio button component and be further optimized.
- There are a few ways to handle multiple radio buttons especially as they get nested into components which is out of the scope of this demo.
Links 🔗
useState
Input
Checked
currentTarget
❤️❤️❤️
Social
Twitter
Linkedin
Portfolio
Github
🤘
Thank you for reading happy coding!
Github Repo
Top comments (0)