Selectors are important in software development. They are useful in forms, settings, and other features that require the user's input. Selectors, though, are not built equal. Different selectors have different jobs. Without a dedicated UX/UI designer, you may use a radio where you need a checkbox.
This article will cover radio groups and checkboxes. We will touch on their history and define them. Then, we discuss the ideal and unacceptable use cases for each selector. Two terms you will often see in this article are:
- Mutually Exclusive: options that cannot occur at the same time
- Mutually Inclusive: options that can occur at the same time.
Finally, this article shows you how to build these selectors with React and Material UI. These code blocks will cement the logic behind each of the selectors. For this portion of the article, you need the following prerequisite knowledge:
- JavaScript fundamentals
- React fundamentals
The Checkbox
The checkbox is a graphic component that helps a user choose from a list. The checkbox is based on skeuomorphism, a design system that models digital assets after real-life objects. The real-life object that the digital checkbox mirrors is the paper and pen list. See Fig 1:
Imagine you have to keep track of your chores at home. Have you washed the dishes? Check. Did you do the laundry? Check. Have you cooked for granny? Check. These are Boolean choices. The answer could only be 'yes' or 'no'. And this is the original kind of checkbox where choices are mutually exclusive.
But imagine a different non-linear question. How many tech stacks do you know? JavaScript, check. CSS, check. React, Check. Zustand, Check. Redux, learning. This makes things more interesting. The answer is not always binary. This creates a third category which you may know as 'maybe'. The technical term for this state is 'indeterminate'. And any checkbox with an indeterminate state is a Tri-State Checkbox.
Both the classic and the tri-state checkboxes are mutually exclusive. To pick one answer is to invalidate the other(s). But as checkboxes evolved, they became mutually inclusive. We started using them to provide a list of options where users can pick multiple. For example, what programming languages, frameworks, and libraries do you know? Pick as many as you like.
Here are more examples of checkbox use cases:
- A job board user wants to pick all the job titles they are interested in.
- A fashion e-commerce store allows users to pick the colors, and sizes they want for a pair of shoes.
- A product manager wants to pick which team members have edit access to the Jira workspace.
- A first-time Spotify user wants to pick their favorite music genres and artists
How to build a Checkbox Component with React and Material UI
In this mini-project, we create a checkbox to select some of our favorite colors.
import React, { useState } from "react";
import {
FormGroup,
Checkbox,
Box,
Stack,
Typography,
FormControlLabel,
} from "@mui/material";
export default function TestingCheckbox() {
const [selectedColors, setSelectedColors] = useState([]);
const colors = [
{ name: "Blue", code: "#2196F3" },
{ name: "Green", code: "#4CAF50" },
{ name: "Red", code: "#F44336" },
];
const handleClick = (color) => {
//check if color already exists
if (selectedColors.some((c) => c.name === color.name)) {
// if yes, remove it from the array
setSelectedColors((prevSelectedColors) =>
prevSelectedColors.filter((item) => item.name !== color.name)
);
} else {
//otherwise add it to the array
setSelectedColors((prevSelectedColors) => [...prevSelectedColors, color]);
}
};
Here’s how it works:
- Import React, and useState
- Import Form Group, Checkbox, and other MUI components for styling
- Create a function named TestingCheckbox
- Inside TestingCheckbox, create a state variable named selectedColors. SelectedColors is an array that will hold any color a user picks from the checkbox.
- Create an array of colors
- Create a function named handleClick. Handle click will do the following:
- Receive color as a variable
- Check the selectedColors array to see if color is already present. We do this using the .some() array method
- If color is already present in selectedColors, remove it using the .filter() array method.
- If color is not present in the selectedColors array add it using the spread operator
Next, we build the interface for the checkbox and attach the above logic to it. Here’s the code:
import React, { useState } from "react";
import {
FormGroup,
Checkbox,
Box,
Stack,
Typography,
FormControlLabel,
} from "@mui/material";
export default function TestingCheckbox() {
…
…
return (
<>
<FormGroup>
{colors.map((color, idx) => (
<FormControlLabel
control={<Checkbox />}
value={color}
label={`${color.name}`}
onChange={() => handleClick(color)}
/>
))}
</FormGroup>
</>
);
}
Here’s how it works:
- Use the FormGroup component from MUI.
- Inside the FormGroup component, nest a FormControlLabel
- Inside the FormControlLabel do the following:
- Add a control prop to decide how you want the form to be controlled. Since we are building a Checkbox, add the MUI Checkbox component.
- Add a value prop to determine what value the checkbox holds. In this case, we want the color object to be the value.
- Add a label prop to determine which text is rendered alongside the checkbox. We use the name of the color in this case.
- Add an onChange prop to determine what happens when the checkbox is checked or not. Let the prop value be a function that calls the handleClick function you created earlier. Pass color as the parameter.
- Test the component by logging selectedColors to the console. Whatever you check will appear in the array. And whatever you uncheck will be removed from the array.
Look below for a gif of the expected behavior.
The Radio Group
A radio group is a collection of mutually exclusive options where selecting one deselects the others. You could also call it an option group. Also based on skeuomorphism, the radio group evolved from the buttons of car radios.
One way to visualize this is to imagine 2 buttons on a car radio. Once you click button-one, it sinks in and stays that way. But when you click button-two, it sinks in and button-one pops back up. It is impossible to select two buttons at the same time
One earliest adaptations of car radio buttons was in the BitRectEditor for Smalltalk. It was a 1975 digital sketch board that had several color palettes. You could only pick one color palette at a time. This principle has evolved into the 21st century in other forms. You should only use a radio group when only one option out of several can be true at a time. Some examples are as follows:
- A survey field with the answers 'Strongly Agree, Agree, Disagree, Strongly Disagree'.
- A form field asking users to pick their gender
- A field allowing a user to pick one mode of transportation on Google Maps.
- A page outlining the subscription plans and asking a user to pick one.
How to build a radio group in React and MaterialUI
Now, we build a mini project. This project is similar to the last one. But this time, we want a user to pick one color. Like the last example, we first build the handler function, then the interface. Here’s the code:
import React, { useState } from "react";
import {Radio, RadioGroup, FormControlLabel, FormControl, FormLabel } from "@mui/material";
export default function SampleRadioGroup() {
const [favoriteAnimal, setFavoriteAnimal] = useState("");
const handleRadioChange = (event) => {
setFavoriteAnimal(event.target.value);
};
To build the logic for the Radio group, do the following:
- Import React
- Import FormGroup, RadioGroup, and other related MUI components.
- Create the SampleRadioGroup function. Inside the SampleRadioGroup function, do the following:
- Create a state variable that keeps track of the chosen favorite animal.
- Create a callback function that updates favoriteAnimal with the value of the future event. In this case, the event is when a clicks a radio button.
…
return (
<>
<FormControl>
<FormLabel id="favorite-animal-label">
My favourite animal is a {favoriteAnimal && favoriteAnimal}
</FormLabel>
<RadioGroup
aria-labelledby="favorite-animal-label"
defaultValue=""
name="favorite-animal-group"
value={favoriteAnimal}
onChange={handleRadioChange}
>
<FormControlLabel value="Cat" control={<Radio />} label="Cat" />
<FormControlLabel value="Dog" control={<Radio />} label="Dog" />
<FormControlLabel
value="Elephant"
control={<Radio />}
label="Elephant"
/>
</RadioGroup>
</FormControl>
);
</>
)
}
Here’s how it works:
Inside the return statement, do the following:
- Add a FormControl component.
- Nest a FormLabel component inside the FormControl. This serves as the title for the radio group.
- After FormLabel add a RadioGroup component.
- Inside RadioGroup use the following props:
- Set defaultValue as an empty string
- Set the value prop to favoriteAnimal. This way, whatever the favouriteAnimal state variable contains will automatically become the value/choice of the radio group.
- Set the onChange prop to handleRadioChange. This way, any radio button clicked within the radio group will trigger the callback function, handset the state of favoriteAnimal.
- Finally, add a FormControlLabel for each animal. Use the following props:
- Set Value to the animal’s name
- Set the control type to an MUI Radio component
- Set the label to the animal’s name.
- Test the Radio group by clicking on any animal. The title should read ‘My favorite animal is (whatever animal you pick)’. See below for a gif of the expected behavior
Conclusion
Picking the right selector is crucial to the user experience. As a rule of thumb, radio groups are useful when a user can only pick one of the options. Checkboxes are useful when a user can pick one, or multiple options from a list. Since these selectors are all based on real-life objects, you can imagine how you would use these selectors in the real world.
Top comments (0)