Part 4: Forms and User Input

Introduction

Forms are the primary way users send data to a server. Every login page, search box, settings panel, and data entry screen is built on HTML form elements. Getting forms right — semantically correct labels, proper input types, built-in validation — reduces the amount of JavaScript needed and makes pages more accessible by default.

This part covers every form element I use regularly, along with the patterns that make forms work correctly without relying entirely on custom JavaScript.


The <form> Element

<form action="/submit" method="post">
  <!-- form fields -->
  <button type="submit">Submit</button>
</form>

Key attributes:

Attribute
Values
Purpose

action

URL

Where to send the form data. Defaults to current URL if omitted.

method

get, post

HTTP method. get appends data to URL; post sends in body.

enctype

application/x-www-form-urlencoded, multipart/form-data, text/plain

How to encode form data. Required multipart/form-data for file uploads.

novalidate

boolean

Disables browser's built-in validation (useful when handling validation in JavaScript).

autocomplete

on, off

Whether to allow browser autocomplete.

GET vs POST:

  • GET — data goes in the URL query string. Use for search forms, filtering, anything that should be bookmarkable.

  • POST — data goes in the request body, not visible in the URL. Use for logins, data submissions, anything that modifies server state.


Labels

Labels are the most important accessibility element in a form. Every interactive form field needs a label.

Explicit Label

The for attribute matches the id of the input. Clicking the label focuses the input — this is especially important on mobile where tap targets are small.

Implicit Label (Wrapped)

When the input is inside the <label>, the for/id linkage is implicit. Both styles are valid.

Never use placeholder text as a substitute for a label. Placeholders disappear when typing starts and do not work as accessible labels. They are appropriate as examples of expected format, not as the field's purpose.


The <input> Element

<input> is the most versatile form element. The type attribute controls what kind of input it renders.

Text Inputs

Using the correct type does several things without any JavaScript:

  • Triggers the right keyboard on mobile (numeric for tel, @ key for email)

  • Enables browser-native format validation

  • Enables browser autocomplete for the correct category of data

Number Inputs

Date and Time Inputs

Date inputs render a date picker natively in most browsers, removing the need for a JavaScript date picker library for basic use.

Checkbox

For multiple independent options:

checked pre-checks the box.

Radio Buttons

Radio buttons form a group where only one can be selected. Group them with the same name:

File Input

For multiple files:

The form must use enctype="multipart/form-data" for file uploads to work.

Hidden Input

Hidden inputs submit data with the form without being visible to the user. Commonly used for CSRF tokens, pre-filled values, or state management.

Range Slider

Color Picker


<textarea>

Multi-line text input:

rows and cols set the default visible size. resize: none in CSS if you want to prevent user resizing.


<select> and <option>

Dropdown menu:

Pre-select an option with selected:

Option Groups

Multiple Select


<fieldset> and <legend>

Group related inputs visually and semantically:

Screen readers announce the <legend> text as context for the fields within the <fieldset>.


Buttons

Always specify type. Without it, the default is submit, which means buttons inside a form will submit it unless explicitly typed otherwise. This catches many developers by surprise.


Built-in Validation Attributes

HTML provides validation attributes that work without JavaScript:

Attribute
Purpose

required

Field must have a value

minlength="n"

Minimum character count

maxlength="n"

Maximum character count

min="n"

Minimum value (number/date inputs)

max="n"

Maximum value (number/date inputs)

pattern="regex"

Value must match regular expression

type="email"

Browser validates email format

type="url"

Browser validates URL format

Use the :valid and :invalid CSS pseudo-classes to style fields based on validation state:


Accessibility Best Practices for Forms

  1. Every input has a visible label — do not rely on placeholder text alone

  2. Group related fields with <fieldset> and <legend>

  3. Provide error messages — don't just highlight in red, say what's wrong in text

  4. Associate error messages with inputs using aria-describedby:

  1. Use autocomplete attributes to help password managers and browsers fill fields correctly:


A Complete Form Example


Summary

Element
Purpose

<form action method>

Container for all form fields

<label for>

Accessible label linked to an input

`<input type="text

email

`<input type="checkbox

radio">`

<input type="file">

File uploads

<input type="hidden">

Hidden data (CSRF tokens etc.)

<textarea>

Multi-line text input

<select> / <option>

Dropdown menus

<fieldset> / <legend>

Grouping related fields

`<button type="submit

reset

required, pattern, min, max

Built-in validation

autocomplete

Hint for browser/password manager

aria-describedby

Link error messages to inputs


Up Next

Part 5 covers accessibility, SEO fundamentals, and HTML5 features that make pages more robust and discoverable.

Last updated