React Form with Checkbox
Checkbox groups store their state as an array of selected values, which requires a different state pattern than simple text inputs. The toggle logic — add if not present, remove if already there — is a one-liner with filter and spread. A "Select all" feature makes the component immediately useful for real-world forms like skill selectors or preferences.
The challenge
Handling checkbox groups and syncing state can become messy in React forms, especially when implementing select-all and toggle logic.
- Toggling a checkbox in an array state without mutating the original array
- Implementing "Select all" and "Deselect all" without duplicating state logic
- Syncing the "Select all" checkbox indeterminate state when only some options are checked
- Knowing which items are selected when submitting the form alongside other field types
Working code example
Here is a complete, self-contained working example you can drop directly into any React project. It uses Tailwind CSS for styling and requires no external dependencies beyond React itself.
import { useState } from 'react';
const SKILLS = ['React', 'TypeScript', 'Node.js', 'CSS', 'Testing'];
export default function CheckboxGroup() {
const [selected, setSelected] = useState([]);
const [submitted, setSubmitted] = useState(false);
const toggle = (skill) => {
setSelected((prev) =>
prev.includes(skill) ? prev.filter((s) => s !== skill) : [...prev, skill]
);
};
const selectAll = () => setSelected([...SKILLS]);
const clearAll = () => setSelected([]);
const allSelected = selected.length === SKILLS.length;
const handleSubmit = (e) => {
e.preventDefault();
if (!selected.length) { alert('Please select at least one skill'); return; }
setSubmitted(true);
};
if (submitted)
return (
<div className="p-6 bg-green-50 rounded-2xl text-green-700">
<p className="font-semibold">Skills submitted!</p>
<p className="text-sm mt-1">{selected.join(', ')}</p>
</div>
);
return (
<form onSubmit={handleSubmit} className="max-w-sm mx-auto p-6 bg-white rounded-2xl shadow space-y-4">
<h2 className="text-xl font-bold text-gray-800">Your Skills</h2>
<div className="flex gap-3">
<button type="button" onClick={allSelected ? clearAll : selectAll}
className="text-xs px-3 py-1 rounded-full border border-teal-600 text-teal-600 hover:bg-teal-50 transition">
{allSelected ? 'Deselect all' : 'Select all'}
</button>
<span className="text-xs text-gray-400 self-center">{selected.length} / {SKILLS.length} selected</span>
</div>
<div className="space-y-2">
{SKILLS.map((skill) => (
<label key={skill} className="flex items-center gap-3 cursor-pointer group">
<input
type="checkbox"
checked={selected.includes(skill)}
onChange={() => toggle(skill)}
className="w-4 h-4 accent-teal-600 rounded"
/>
<span className={`text-sm ${selected.includes(skill) ? 'text-teal-700 font-medium' : 'text-gray-700'}`}>
{skill}
</span>
</label>
))}
</div>
<button type="submit"
className="w-full bg-teal-600 text-white font-semibold py-2 rounded-lg hover:bg-teal-700 transition">
Save Skills
</button>
</form>
);
}How ReactForm.co helps
ReactForm's visual builder handles all of the above — checkbox configuration, validation rules, state management, and responsive layout — without writing a single line of code. Drag fields onto the canvas, configure their properties in the sidebar, and get production-ready React output. You can publish the form and collect responses instantly, or export the JSX to drop into your own codebase.
Build this form visuallyFrequently asked questions
How do I store checkbox group state in React?
Use an array of selected values in useState. When a checkbox is toggled, add the value if it is not already in the array, or remove it if it is: setSelected(prev => prev.includes(val) ? prev.filter(v => v !== val) : [...prev, val]). This pattern avoids mutating state and works for any number of options.
How do I make a "Select all" checkbox with an indeterminate state?
Track the indeterminate state in a useEffect and set it directly on the DOM element via a ref: checkboxRef.current.indeterminate = selected.length > 0 && selected.length < options.length. React does not support the indeterminate attribute declaratively, so you need to use a ref for this.
What is the difference between a checkbox group and a single checkbox?
A single checkbox stores a boolean in state. A checkbox group stores an array of selected values. For a single checkbox, use onChange={e => setBool(e.target.checked)}. For a group, use the toggle pattern with an array. Always use type="checkbox" and read e.target.checked, not e.target.value.
Related topics
Build this form visually — no code needed
ReactForm.co handles checkbox fields, validation, conditional logic, and responsive layout automatically. Publish in minutes and collect responses for free.

