HTML Forms — Validation & Accessibility
debt(d5/e3/b3/t7)
Closest to 'specialist tool catches it' (d5). The detection_hints.tools list includes axe, lighthouse, and wave — all specialist accessibility and audit tools. Missing labels, wrong input types, and accessibility violations are not caught by a compiler or default linter, but are reliably flagged by these specialist tools when run deliberately.
Closest to 'simple parameterised fix' (e3). The quick_fix is to swap custom JS widgets or mis-typed inputs for native HTML elements. This is a small, localised refactor — replacing a div-based dropdown with a select, or adding a label — confined to individual components rather than spanning the whole codebase.
Closest to 'localised tax' (b3). The applies_to scope is web contexts only, and the burden is per-form or per-component. Each form that uses incorrect structure imposes a tax on that component (extra JS to recreate accessibility, maintenance of custom widgets), but it doesn't structurally constrain unrelated parts of the codebase.
Closest to 'serious trap' (t7). The misconception field explicitly states that HTML5 form validation is believed to remove the need for server-side validation — a dangerous belief that contradicts security fundamentals. Client-side validation can be trivially bypassed via raw HTTP requests or disabling JS, but many competent developers coming from a frontend-first background assume the browser enforces the constraint end-to-end. This contradicts how similar concepts (e.g. required attributes) appear to work at first glance.
Also Known As
TL;DR
Explanation
HTML5 input types give free validation and mobile-optimised keyboards: email, tel, number, date, url, color. Constraint validation attributes: required, minlength, maxlength, pattern (regex), min, max, step. The browser validates on submit and shows native UI unless novalidate is added. For custom validation, use the Constraint Validation API: input.setCustomValidity('message'). Accessibility: always associate <label> with input via for/id or wrapping; use aria-describedby for hint text; aria-invalid='true' on failed fields; aria-live='polite' on error containers. Never rely solely on placeholder — it disappears on focus and has poor contrast. Server-side validation (PHP) is mandatory regardless of client validation — never trust the client.
Common Misconception
Why It Matters
Common Mistakes
- Input without a label — placeholder is not a substitute; it disappears when the user types.
- Not using the correct input type (email, tel, number) — loses browser-native validation and mobile keyboard.
- Form submission via JavaScript without a fallback for disabled JS users.
- Not using autocomplete attributes — browsers cannot autofill correctly without them.
Code Examples
<input type="text" placeholder="Enter your email">
<input type="text" id="pass">
<!-- Label association, correct input type, built-in validation -->
<label for="email">Email address</label>
<input
type="email"
id="email"
name="email"
required
autocomplete="email"
aria-describedby="email-hint"
>
<span id="email-hint">We'll never share your email</span>
<!-- Password with show/hide -->
<label for="password">Password</label>
<input type="password" id="password" name="password"
required minlength="8" autocomplete="current-password">