Text and choice controls
Checkboxes and radio buttons
Model independent boolean choices with checkboxes and one choice from a set with radio buttons that share a name.
A checkbox is a yes-or-no question. Radio buttons are a pick-one question. That’s the whole distinction, and picking the right one keeps the data clean.
Checkboxes
Each checkbox stands on its own:
<label>
<input name="newsletter" type="checkbox" value="yes">
Send me the weekly newsletter
</label>
Checked, it sends newsletter=yes. Unchecked, it sends nothing. There’s no newsletter=no in the request. The key isn’t there.
On the server, treat that absence as false only if that is what the form means. And write the value attribute. Without it a checked box sends newsletter=on, which works but reads badly in your server code.
Radio buttons
Radio buttons become a group when they share a name:
<fieldset>
<legend>Delivery speed</legend>
<label>
<input name="delivery" type="radio" value="standard" checked>
Standard
</label>
<label>
<input name="delivery" type="radio" value="express">
Express
</label>
</fieldset>
Select Express and the browser clears Standard. The request contains delivery=express, one value for the group.
One failure I see often: a radio group with no checked option. The person skips it, nothing is selected, and the request has no delivery key at all. Mark a default with checked, or make the server treat the missing key as a validation error.
Stable values
Give every option an explicit value and keep it stable. The label is for people. The value is what the server stores.
You can rename “Express” to “Next day” in the label without touching the database. Change the value and every stored record stops matching.
Allowlist on the server
The server must check the value against the list of options it knows. Someone can send delivery=teleport even though no such option exists in the page. Reject anything not on the list.
Several true answers
When more than one answer can be true, use separate checkboxes. If they share a name, the request repeats the key:
topic=html&topic=css
Read them with an API that keeps every entry, like getAll('topic'). A parser that turns the body into a plain object keeps only the last one, and you silently lose data.
Try this: submit the delivery form with each option, then with the checkbox on and off. Look at the payload each time. Pay attention to what is missing more than to what is there.
Lesson completed