Forms Deep Dive
Every input, validation, labels, and the modern <dialog>.
Forms are how the web gets data from users instead of just showing things tothem. They're also the area where new developers reach hardest for JavaScript when they shouldn't. Modern HTML has so much built-in form behavior that you can ship a complete login flow with zero JS and never sacrifice UX.
The form element
<form action="/signup" method="post">
<label for="email">Email</label>
<input id="email" name="email" type="email" required />
<button type="submit">Sign up</button>
</form>Two attributes you'll set on every <form>: action (where the data goes) and method (usually get or post). With nothing else, this form actually works. Submit it and the browser POSTs to /signup with the email field.
name attribute, an input's value is not submitted with the form. This is the most common forgotten-detail in beginner forms.The input types you should know
The type attribute does a lot more than change the icon. It changes the mobile keyboard, native validation, and how assistive tech describes the field.
type="text"- generic single-line. The default.type="email"- validates basic email shape, shows the email keyboard on mobile (with the @ key).type="password"- masks input, opts out of autocomplete by default.type="tel"- phone numbers. Doesn't validate format (formats vary by country) but shows the numeric keypad on mobile.type="number"- numeric only. Useinputmode="numeric"on text inputs if you want a number keypad without the spinner buttons.type="date"- opens a native date picker.type="datetime-local",type="time", andtype="month"are siblings.type="range"- a slider.type="color"- a native color picker.type="file"- file upload. Addaccept="image/*"oraccept=".pdf"to restrict.type="checkbox"- independent on/off toggles.type="radio"- mutually exclusive options. Share anameacross siblings to group them.
Labels: not optional
Every input needs a label. There are two ways to associate them:
<!-- Method 1: for + id -->
<label for="email">Email</label>
<input id="email" name="email" type="email" />
<!-- Method 2: wrap the input -->
<label>
Email
<input name="email" type="email" />
</label>Both work. Method 1 is more flexible for layout (you can position the label anywhere). Note: in React/JSX, for becomes htmlFor because for is a reserved word.
Native validation
HTML has built-in validation. You don't need JS to require a field, check a pattern, or set a length.
required- must have a value.minlength/maxlength- character bounds.min/max- numeric bounds fornumber,date, etc.pattern- a regex the value must match.type="email"/type="url"- type-specific built-in validation.
<label for="username">Username</label>
<input
id="username"
name="username"
type="text"
required
minlength="3"
maxlength="20"
pattern="[a-zA-Z0-9_]+"
title="Letters, numbers, and underscores only"
/>On submit, the browser blocks the form and shows a tooltip pointing at the offending field. Style invalid fields with the :invalid CSS pseudo-class.
Beyond input: select, textarea, datalist
<!-- Dropdown -->
<label for="role">Role</label>
<select id="role" name="role">
<option value="">Pick one</option>
<option value="admin">Admin</option>
<option value="member">Member</option>
</select>
<!-- Multi-line text -->
<label for="bio">Bio</label>
<textarea id="bio" name="bio" rows="4" maxlength="500"></textarea>
<!-- Autocomplete suggestions on a regular input -->
<label for="city">City</label>
<input id="city" name="city" list="cities" />
<datalist id="cities">
<option value="Tokyo" />
<option value="Paris" />
<option value="Lagos" />
<option value="Sao Paulo" />
</datalist><datalist> is underused: it gives you native autocomplete suggestions without the user being forced to pick from the list. They can also type their own value.
The modern dialog element
<dialog> is a native modal. No library needed. It handles focus trapping, the backdrop, and ESC-to-close.
<button onclick="myDialog.showModal()">Open</button>
<dialog id="myDialog">
<form method="dialog">
<p>Are you sure?</p>
<button value="cancel">Cancel</button>
<button value="confirm">Yes, delete</button>
</form>
</dialog>A form with method="dialog" inside a dialog automatically closes it on submit and returns which button was clicked. Total magic, zero JS.
The popover API
Newer than <dialog> and useful for tooltips, menus, and any non-modal floating UI:
<button popovertarget="menu">Show menu</button>
<div id="menu" popover>
<p>I'm a popover. Click anywhere to dismiss.</p>
</div>Add popover to any element to make it a popover. Wire it up with popovertarget on a button. Light-dismiss (click outside to close), top-layer rendering, and focus management are all handled for you.
Try it: a real signup form
Try submitting it empty. Notice the browser refuses and points to the first empty field. Try entering "a" for the name - it tells you the minimum length. That's zero lines of JS validation.
Quick quiz
An input has no name attribute. What happens on submit?
Recap
<form>takesactionandmethod. Every input needs aname.- Pick
typedeliberately - it changes the mobile keyboard, native validation, and accessibility. - Use real
<label>s. Placeholder is for examples, not titles. - Native validation:
required,minlength,maxlength,pattern,min,max. <select>,<textarea>,<datalist>cover dropdowns, multiline, and autocomplete.<dialog>and the popover API give you modals and floating UI without libraries.