Week 9 · Lesson 18

Contact Forms — Accessible, Validated, Working

Week 9 · 75 minutes · Year 10 Industrial Technology — Multimedia

IND5-2IND5-3IND5-5IND5-7

Learning intentions

  • I can build an accessible HTML form using label/input pairing correctly.
  • I can use HTML5 input types (email, tel, url, number) for appropriate data.
  • I can group related fields with
    and .
  • I can connect a form to Formspree for a real submission.

Success criteria

  • My portfolio has a working contact form.
  • Every input has a
  • At least one input uses an HTML5 type (email, tel, url, or number).
  • Related fields are grouped inside
    with a .

Do Now · 5 min

Fill out a good form and a bad form in your head. What makes one feel right and the other frustrating?

Common form crimes:

I Do · ~10 min Teacher demonstration

Step 1 — The form skeleton

<form action="https://formspree.io/f/YOUR_ID" method="POST">
  ... inputs go here ...
  <button type="submit">Send</button>
</form>

Step 2 — Every input needs a label (this is non-negotiable for accessibility)

<!-- PATTERN 1: label + input linked by for/id -->
<label for="email-field">Email address</label>
<input type="email" id="email-field" name="email" required>

<!-- PATTERN 2: label wraps the input (no for/id needed) -->
<label>
  Full name
  <input type="text" name="name" required>
</label>
Why this matters: a screen reader user tabs through the form. When they reach the email input, the screen reader announces the label. Without a linked label, they hear "edit text" — completely useless.

Step 3 — HTML5 input types (use the right one!)

type="text"       /* generic single-line */
type="email"      /* triggers email keyboard on phone, validates @ */
type="tel"        /* triggers phone number keyboard on phone */
type="url"        /* validates URL format */
type="number"     /* numeric only, with up/down arrows */
type="date"       /* opens a calendar picker */
type="color"      /* opens a colour picker */
type="range"      /* slider */
type="password"   /* masks input */
type="file"       /* file picker */
type="hidden"     /* not visible, used for tracking */

Step 4 — Text areas, selects, radios, checkboxes

<!-- Multi-line text -->
<label for="message">Your message</label>
<textarea id="message" name="message" rows="5" required></textarea>

<!-- Dropdown -->
<label for="topic">Topic</label>
<select id="topic" name="topic">
  <option value="question">A question</option>
  <option value="feedback">Feedback</option>
  <option value="work">Work experience</option>
</select>

<!-- Radio (one choice) -->
<fieldset>
  <legend>How did you find me?</legend>
  <label><input type="radio" name="source" value="google"> Google</label>
  <label><input type="radio" name="source" value="friend"> Friend</label>
  <label><input type="radio" name="source" value="school"> School</label>
</fieldset>

<!-- Checkbox (multiple choices) -->
<fieldset>
  <legend>Interests</legend>
  <label><input type="checkbox" name="interests" value="design"> Design</label>
  <label><input type="checkbox" name="interests" value="code"> Coding</label>
</fieldset>

Step 5 — Fieldset and legend group related fields

<fieldset> with <legend> tells a screen reader "these fields belong together". The legend is announced before each field in the group.

Step 6 — HTML5 validation (free, built into the browser)

<input type="email" name="email" required>
<input type="text" name="username" required minlength="3" maxlength="20">
<input type="number" name="age" min="13" max="120">
<input type="tel" name="phone" pattern="[0-9]{10}">
<input type="text" name="title" placeholder="e.g. Year 10 student" disabled>

We Do · ~15 min Guided build

Style the form to match your portfolio:

form { max-width: 500px; margin: 0 auto; }
fieldset { border: 1px solid #e4e7ec; border-radius: 8px; padding: 1rem; margin-bottom: 1rem; }
legend { font-weight: 700; padding: 0 0.5rem; }

label { display: block; font-weight: 600; margin-bottom: 0.3rem; }
input, textarea, select {
  width: 100%;
  padding: 0.7rem;
  border: 2px solid #e4e7ec;
  border-radius: 6px;
  font: inherit;
}
input:focus, textarea:focus, select:focus {
  outline: none;
  border-color: #1f3a68;
}

button[type="submit"] {
  background: #1f3a68;
  color: white;
  border: 0;
  padding: 0.8rem 1.5rem;
  border-radius: 6px;
  cursor: pointer;
}

You Do · ~35 min Independent practice

Add a contact section (or contact.html page) to your portfolio:

  1. Wrap everything in a <form> with action (Formspree or mailto:).
  2. Include at least: Name (text), Email (type="email"), Message (textarea).
  3. Every field has a linked <label>.
  4. Use <fieldset>+<legend> to group at least one set of related fields.
  5. Use required on at least one field.
  6. Style the form to match your portfolio palette and fonts.
  7. Test: submit the form; does anything happen?
  8. Build a proper footer for the page.

Free services for real submissions (no backend needed):

Differentiation

Support

Pre-built form HTML with comments; student swaps in Formspree URL and styles it.

Core

Build from scratch using all 3 semantic grouping elements (label/fieldset/legend).

Extension

Add HTML5 pattern validation with a regex (e.g. phone number pattern). Use :invalid CSS pseudo-class to style fields that fail validation.

Exit Ticket · 5 min

Exit ticket

1. Why does every input need a label?

_______________________________________________________

2. What's the correct input type for each?

Email: _________   Phone: _________   Age: _________

3. Which tag groups related fields? _______

4. Paste the HTML of your favourite input from today's work:

_______________________________________________________

Resources for this lesson

📚 Deeper Reading

External references drawn from Shay Howe's "Learn to Code HTML & CSS" and University of Michigan's "Web Design for Everybody" Coursera specialization. All credit to original authors.