FullStack Course LogoFullStack Course
Module: HTML
HTML·009·9 MIN READ

009: Forms II

TOPICS COVERED: Forms II

Learning outcomes

By the end of this lesson, you can add radio buttons, checkboxes, select menus, text areas, date and number controls; group related choices with fieldset and legend; explain single versus multiple selection; and choose submit or reset controls deliberately.

Prerequisites and retrieval

Open 008's registration form. For each control, identify its visible label, unique ID, submission name, and current value. Then predict which piece of request data vanishes if you remove its name.

Terminology

  • Radio group: Same-named radio inputs where at most one can be checked at a time. — Source: WHATWG: Radio Button state
  • Checkbox: An input in the checkbox state: a binary on/off control, or one member of a same-name set. — Source: WHATWG: Checkbox state
  • Select: “The select element represents a control for selecting amongst a set of options.” — Source: WHATWG: The select element
  • Option: “The option element represents an option in a select element.” — Source: WHATWG: The option element
  • Textarea: “The textarea element represents a multiline plain-text edit control for its raw value.” — Source: WHATWG: The textarea element
  • Fieldset: “The fieldset element represents a set of form controls optionally grouped under a common name.” — Source: WHATWG: The fieldset element
  • Legend: “The legend element represents a caption for the rest of the contents of the fieldset element’s parent fieldset element.” — Source: WHATWG: The legend element
  • Reset: input type=reset restores all controls to their initial values without clearing server data. — Source: WHATWG: Reset Button state
  • Initial value: The default value or selected/checked state declared in markup that reset restores. — Source: WHATWG: Form elements
  • Radio button (input type=radio): "The input element with type radio represents a radio button — a control that allows selection of a single value from a set." — Source: WHATWG: Radio Button state
  • Select multiple: "The select element with multiple attribute allows multiple options to be selected." — Source: WHATWG: Select element
  • Optgroup: "The optgroup element represents a group of option elements with a common label." — Source: WHATWG: Optgroup element

Mental model: label the question and every answer

A radio-button set has two jobs to do. The legend states the question shared by the set, while each individual label identifies one possible answer. The shared name makes the radios mutually exclusive; their distinct IDs give the labels unambiguous targets.

html
<fieldset>
  <legend>Preferred contact method</legend>
  <input type="radio" id="contact-email" name="contact-method" value="email">
  <label for="contact-email">Email</label>
  <input type="radio" id="contact-phone" name="contact-method" value="phone">
  <label for="contact-phone">Phone</label>
</fieldset>

With Email selected, the form contributes contact-method=email. If each radio had a different name, the browser would treat them as separate groups and permit both choices. That would no longer match a question that expects exactly one answer.

Control choices

Reach for a checkbox when the user is making an independent yes/no choice:

html
<input type="checkbox" id="updates" name="updates" value="yes">
<label for="updates">Send occasional project updates</label>

An unchecked checkbox contributes no entry at all. The server has to interpret that absence correctly; whether to add a hidden field is an application-specific decision. For several independent interests, give the checkboxes the same name and different values when the server expects multiple entries.

Use select when the user must choose from a constrained list:

html
<label for="topic">Main topic</label>
<select id="topic" name="topic">
  <option value="html">HTML review</option>
  <option value="accessibility">Accessibility audit</option>
</select>

The text inside an option is for the user; its value is what the server receives. If value is omitted, the option text is submitted instead. A native select is usually the better starting point than a custom scripted replacement.

For text that may span multiple lines, use textarea:

html
<label for="message">Message</label>
<textarea id="message" name="message" rows="6" cols="40"></textarea>

A textarea's initial value is the text between its opening and closing tags, not a value attribute. Whitespace placed there can become part of that initial content. rows and cols are intrinsic sizing hints; CSS will control the eventual layout.

type="date" gives the browser enough information to provide a localized date interface while submitting a normalized date string such as 2026-09-01. The visible widget differs across browsers. type="number" is appropriate for quantities where numeric ranges and stepping make sense. It is the wrong model for phone numbers, postal codes, card numbers, and other identifiers that can contain non-numeric characters or leading zeros.

More native controls and input hints

Before writing a custom JavaScript widget, check whether HTML already provides a control with the behavior you need. Native behavior usually brings keyboard and assistive-technology support with it.

Group long option lists with optgroup

html
<label for="branch">Preferred branch</label>
<select id="branch" name="branch">
  <optgroup label="North">
    <option value="n1">North Central</option>
    <option value="n2">North Market</option>
  </optgroup>
  <optgroup label="South">
    <option value="s1">South Station</option>
  </optgroup>
</select>

Offer suggestions with datalist

html
<label for="city">City</label>
<input id="city" name="city" list="city-options">
<datalist id="city-options">
  <option value="Chennai">
  <option value="Madurai">
  <option value="Coimbatore">
</datalist>

Unlike select, a datalist normally suggests values without restricting the user to them. If only the listed values are valid, add an appropriate validation rule rather than assuming the suggestions enforce that restriction.

Hint the mobile keyboard with inputmode

inputmode is only a keyboard hint. It does not validate the submitted value:

html
<label for="otp">One-time code</label>
<input id="otp" name="otp" inputmode="numeric" autocomplete="one-time-code">

Start with the semantic input type. Add inputmode when the keyboard you want differs from the one that type alone would suggest.

The multiple attribute is supported by particular controls, including email and file inputs. Its behavior is part of each control's contract, so do not assume that it has one universal meaning across all input types.

Guided example: extend registration

Replace the form with this version:

html
<form action="/register" method="post">
  <p>
    <label for="full-name">Full name</label>
    <input type="text" id="full-name" name="full-name" autocomplete="name">
  </p>
  <p>
    <label for="email">Email address</label>
    <input type="email" id="email" name="email" autocomplete="email">
  </p>
  <fieldset>
    <legend>Preferred contact method</legend>
    <p>
      <input type="radio" id="method-email" name="contact-method" value="email">
      <label for="method-email">Email</label>
    </p>
    <p>
      <input type="radio" id="method-phone" name="contact-method" value="phone">
      <label for="method-phone">Phone</label>
    </p>
  </fieldset>
  <fieldset>
    <legend>Topics of interest</legend>
    <p>
      <input type="checkbox" id="interest-html" name="interest" value="html">
      <label for="interest-html">HTML</label>
    </p>
    <p>
      <input type="checkbox" id="interest-a11y" name="interest" value="accessibility">
      <label for="interest-a11y">Accessibility</label>
    </p>
  </fieldset>
  <p>
    <label for="experience">Years of coding experience</label>
    <input type="number" id="experience" name="experience" min="0" max="80" step="1">
  </p>
  <p>
    <label for="start-date">Preferred start date</label>
    <input type="date" id="start-date" name="start-date">
  </p>
  <p>
    <label for="message">What would you like to learn?</label>
    <textarea id="message" name="message" rows="6" cols="40"></textarea>
  </p>
  <p>
    <button type="submit">Create account</button>
  </p>
</form>

Select Phone, both interests, experience 1, and a date. Trace the resulting entries. The radio contributes one value, the repeated interest name contributes two, and the number and date contribute text representations. The browser does not turn form data into strongly typed values on the server's behalf.

Tab through the groups as well. In a native radio group, arrow keys select radios; Space toggles a focused checkbox. Exact details can vary by browser and platform, which is a reason to test native behavior before replacing it with a custom control.

Intermediate example: complete contact form

html
<form action="/contact" method="post">
  <p>
    <label for="contact-name">Name</label>
    <input type="text" id="contact-name" name="name" autocomplete="name">
  </p>
  <p>
    <label for="contact-email">Email</label>
    <input type="email" id="contact-email" name="email" autocomplete="email">
  </p>
  <p>
    <label for="contact-topic">Topic</label>
    <select id="contact-topic" name="topic">
      <option value="project">Project question</option>
      <option value="feedback">Portfolio feedback</option>
      <option value="other">Other</option>
    </select>
  </p>
  <fieldset>
    <legend>Reply preference</legend>
    <input type="radio" id="reply-email" name="reply" value="email">
    <label for="reply-email">Email reply</label>
    <input type="radio" id="reply-none" name="reply" value="none">
    <label for="reply-none">No reply needed</label>
  </fieldset>
  <p>
    <label for="contact-message">Message</label>
    <textarea id="contact-message" name="message" rows="8" cols="50"></textarea>
  </p>
  <button type="submit">Send message</button>
</form>

The button describes the action instead of using the generic word “Submit.” A reset button is best left out by default: it is easy to activate accidentally and discard entered work. When a real reset requirement exists, use <button type="reset">Reset form</button>, label it clearly, keep it away from submit, and remember what it does. It restores the controls to their markup defaults; it does not undo changes already submitted to the server.

Advanced optional extension: defaults and multiple selection

checked establishes the initial state of a radio or checkbox, and selected establishes the initial option. Defaults should help the user, not quietly make a consent decision for them. In particular, never precheck optional marketing consent.

<select multiple> allows several options to be selected, but the interaction can be difficult to discover and operate, especially when instructions do not account for platform differences. For a short list, a checkbox group is often clearer. If you choose a multiple select, label it, explain the interaction as far as possible without relying on one platform, test keyboard, touch, and assistive-technology use, and make sure the server accepts repeated values.

Common mistakes and debugging

  • Different radio names: they stop behaving as one group.
  • Same ID repeated: labels target ambiguously; IDs remain unique.
  • No fieldset/legend: the shared question may be lost.
  • Checkbox assumed to submit false: unchecked means absent.
  • Phone as number: use type="tel" or text; phone numbers are identifiers.
  • Textarea value attribute: initial content belongs between tags.
  • Empty first option used as a label without guidance: give the select a real label; validation arrives tomorrow.
  • Reset beside submit: omit unless there is proven value.
  • Prechecked consent: require an intentional user choice.

Accessibility, security, and performance

Native grouping communicates relationships and supplies keyboard interaction. Keep legends concise and phrased as the shared question; make every option understandable through its label. Layout alone should not be carrying that meaning. Date controls look different across user agents, so when an exact format matters, provide visible format guidance and validate the value on the server.

Treat every submitted value as untrusted, including select options and hidden or default values that a user can change. Collect only what you need, use HTTPS, validate and authorize on the server, and encode data when displaying it. Contact forms also need spam and rate controls, but those controls should not become inaccessible puzzles. Native controls are generally both efficient and robust; custom selects often bring large scripts and accessibility defects along with them.

Tiered exercises

Level 1: choices

Build one radio group for contact method and one checkbox group for interests. For each possible state, predict the entries that will be submitted.

Level 2: complete

Add select, textarea, date, number, and submit controls to the registration/contact page. Deliberately leave out reset.

Level 3: evaluate

Keyboard-test both groups, inspect the submitted entries, explain unchecked behavior, and compare checkboxes with a multiple select for three interests.

Level 1: use the guided fieldsets. Selecting Email produces contact-method=email; selecting both interests produces interest=html and interest=accessibility; selecting none produces no interest entry.

Level 2: either complete guided registration or intermediate contact form satisfies the markup. Number is used only for years, date for a calendar value, select for constrained topic, textarea for multiline message, and the submit button states its action. Reset is omitted to protect entered work.

Level 3: Tab enters native groups; arrows move/select radios and Space toggles checkboxes according to platform conventions. Checkboxes are clearer for three visible independent choices. A multiple select may save space but needs extra operating knowledge and testing, so it is not automatically “advanced” or better.

Recap and exit questions

Radio buttons represent one choice, checkboxes independent choices, select constrained options, textarea multiline text, and date/number specialized values. Fieldset and legend preserve group meaning.

  1. What makes radio buttons mutually exclusive?
  2. What does an unchecked checkbox submit?
  3. Where is a textarea's initial value written?
  4. Why is a phone number not type="number"?
  5. Why are reset buttons usually omitted?

Try it with your own example

Custom-order forms are a useful place to see these controls working together: each one represents a real decision Rina's customers make. Write this form yourself before looking at the answer.

Rina wants a "custom cake" order form. A customer picks exactly one size (radio), any number of add-ins (checkboxes), and a pickup date. Try writing it first, then compare:

html
<form action="/order-cake" method="post">
  <fieldset>
    <legend>Cake size</legend>
    <input type="radio" id="size-6" name="size" value="6-inch">
    <label for="size-6">6-inch (serves 6–8)</label>
    <input type="radio" id="size-8" name="size" value="8-inch">
    <label for="size-8">8-inch (serves 10–12)</label>
  </fieldset>
  <fieldset>
    <legend>Add-ins</legend>
    <input type="checkbox" id="addin-choc" name="addin" value="chocolate-shavings">
    <label for="addin-choc">Chocolate shavings</label>
    <input type="checkbox" id="addin-nuts" name="addin" value="toasted-nuts">
    <label for="addin-nuts">Toasted nuts</label>
  </fieldset>
  <p>
    <label for="pickup-date">Pickup date</label>
    <input type="date" id="pickup-date" name="pickup-date">
  </p>
  <button type="submit">Send order request</button>
</form>

Now trace the submission yourself for a customer who picks the 8-inch size and both add-ins: you should get size=8-inch, addin=chocolate-shavings, and addin=toasted-nuts as three separate entries under the repeated addin name, not one combined value. If the customer picks no add-ins, the addin key is simply absent from the request. That is the same "unchecked means missing" behavior you saw with Rina's newsletter form's absent fields.

Further reading: MDN — Other form controls covers select, date, and number controls with more browser-by-browser rendering notes.

Official references

Reader page: /html/lesson/009/forms-ii