Why do we need forms?
Forms are a way to get data from the user: name, email, message, option choices, and so on.
- Text fields —
<input>(single-line),<textarea>(multi-line). - Checkboxes — selecting several options from a list.
- Radio buttons — selecting a single option from a list.
- Dropdown lists —
<select>. - Buttons — submit, reset, action.
The <input> tag — a single-line field
<input> is a self-closing tag. Its type is defined by the type attribute:
| Type | Purpose |
|---|---|
text (default) |
An ordinary text field |
password |
Password (characters hidden) |
email |
Email (built-in check for @) |
search |
Search (has a clear button ×) |
number |
Number (↑↓ arrows, min, max, step attributes) |
date |
Date (browser calendar) |
time |
Time |
datetime-local |
Date + time |
range |
Slider |
color |
Color picker |
Input attributes
| Attribute | Purpose |
|---|---|
placeholder |
A hint inside the field (disappears when typing) |
value |
Default value (as if the user had already entered it) |
name |
The field’s name for submission to the server |
required |
The field is mandatory (the form won’t submit without it) |
disabled |
The field is locked (cannot be edited) |
id |
A unique identifier (for linking with <label>) |
autocomplete |
A hint to the browser about what to autofill ("name", "email", "tel"…) |
autocomplete — browser autofill
The autocomplete attribute tells the browser which saved information to insert into the field:
<input type="text" name="fullname" autocomplete="name">
<input type="email" name="email" autocomplete="email">
<input type="tel" name="phone" autocomplete="tel">
autocomplete improves UX: the browser offers saved data in a single click. This is especially important on mobile devices.placeholder is an example of the expected value (for instance, “John Smith”).<label> or a hint is the name of the field (for instance, “Your name”).Styling input
<input> can be styled like any block element:
.field {
width: 100%;
padding: 10px 15px;
border: 1px solid #ccc;
border-radius: 4px;
font-size: 16px;
box-sizing: border-box;
background-color: #fff;
color: #333;
}
box-sizing: border-box for form fields — otherwise padding will increase the element’s total width.accent-color — styling checkboxes and radio buttons
Previously, changing the color of a checkbox or radio button was impossible without hacks. The modern accent-color property solves this in a single line:
/* All interactive elements — in the brand colors */
input[type="checkbox"],
input[type="radio"],
input[type="range"] {
accent-color: #e53935;
}
accent-color has been supported by all modern browsers since 2022. It works for checkbox, radio, range, and progress.The <textarea> tag — a multi-line field
- Unlike
<input>, it has a closing tag:<textarea>...</textarea>. - The text between the tags is the default value.
- The user can resize it (by dragging the corner).
Limiting the size
textarea.field {
min-width: 250px;
max-width: 100%;
min-height: 100px;
max-height: 300px;
font-family: inherit; /* without this — a monospace font! */
}
<textarea> uses a monospace font by default. Set font-family: inherit to inherit the font from the parent.min-width and max-width to the same value to prevent horizontal resizing. Do the same for the height.The <button> tag
Three types of buttons:
| Type | Behavior |
|---|---|
submit |
Submits the form (requires a <form> tag) |
reset |
Resets all fields to their default values |
button |
Does nothing (for JavaScript handlers) |
Styling a button
.button {
padding: 12px 24px;
border: none;
background-color: #e53935;
color: #fff;
font-size: 16px;
font-family: inherit;
cursor: pointer; /* pointer cursor on hover */
border-radius: 4px;
}
border, background, font-family and style them from scratch.cursor: pointer — by default buttons show an arrow cursor rather than a pointer.The <label> tag — a field caption
<label> is a semantic element that links caption text with an input field.
Two ways to link them
1. Wrapping — the input inside the label:
<label>
<span class="hint">Your name</span>
<input type="text" class="field">
</label>
2. The for attribute + id — the label separate from the input:
<label for="user-email">Email</label>
<input type="email" id="user-email" class="field">
<label> automatically focuses the associated input. This is convenient for UX and important for accessibility (screen readers).The <form> tag
<form> groups fields into a single form. Without it, a submit button won’t work.
<form action="/api/contact" method="POST">
<label>
<span class="hint">Name</span>
<input type="text" name="username" required>
</label>
<button type="submit">Send</button>
</form>
| Attribute | Purpose |
|---|---|
action |
The URL where the data is sent |
method |
HTTP method: GET or POST |
<form> is not just a semantic tag. It has practical significance: it groups fields, adds a submit event, and lets a type="submit" button work.Field validation
HTML has built-in validators — checks performed before a form is submitted:
| Method | What it checks |
|---|---|
required |
The field is not empty |
type="email" |
The presence of an @ character |
min / max |
The range of a numeric value |
minlength / maxlength |
Minimum / maximum number of characters |
pattern |
A check against a regular expression |
required (whether it is empty), then type (format), then pattern and other constraints.The :focus and :hover states
:focus — a field in focus
When the user has clicked on a field or navigated to it with the Tab key:
.field:focus {
outline: 2px solid #1976d2;
outline-offset: 2px;
}
:focus-visible — keyboard-only focus
The problem with :focus: the outline appears on mouse clicks too, which annoys designers. The solution is :focus-visible:
/* Remove the outline on a mouse click */
.field:focus {
outline: none;
}
/* Show the outline only during keyboard navigation */
.field:focus-visible {
outline: 2px solid #1976d2;
outline-offset: 2px;
}
:focus-visible has been supported by all modern browsers since 2022. This is the standard approach: elegant for the mouse, accessible for the keyboard.:hover — hovering with the mouse
.field:hover {
border-color: #666;
}
outline for keyboard focus — it is critical for accessibility. Use :focus-visible so the outline appears only during keyboard navigation and not on a mouse click.The outline property
outline is an outline around an element that does not affect its dimensions or layout.
| Property | What it sets |
|---|---|
outline-width |
The thickness of the outline |
outline-style |
solid, dotted, dashed, none |
outline-color |
The color of the outline |
outline-offset |
The distance from the element’s edge to the outline |
outline |
Shorthand: width style color |
outline is not part of the box model — even with border-box it does not change the element’s size. This is the key difference from border.Grouping selectors
If several elements share the same styles, their selectors can be listed separated by commas:
/* Instead of duplication: */
.field:focus,
.button:focus {
outline: 2px solid #1976d2;
outline-offset: 2px;
}
/* The same fonts for headings: */
h1,
h2,
h3 {
font-family: "Segoe UI", sans-serif;
}
Form structure: a complete example
<form class="contact-form" action="/api/contact" method="POST">
<div class="form-row">
<label class="form-group">
<span class="form-hint">Your name</span>
<input type="text" class="field"
name="username" placeholder="John Smith" required>
</label>
</div>
<div class="form-row">
<label class="form-group">
<span class="form-hint">Email</span>
<input type="email" class="field"
name="email" placeholder="name@example.com" required>
</label>
</div>
<div class="form-row">
<label class="form-group">
<span class="form-hint">Message</span>
<textarea class="field"
name="message" placeholder="Your message..." required></textarea>
</label>
</div>
<div class="form-row">
<button type="submit" class="button">Send</button>
</div>
</form>
/* CSS for spacing between form rows */
.form-row:nth-child(n+2) {
margin-top: 20px;
}
.form-hint {
display: block;
margin-bottom: 6px;
font-weight: 600;
}
Debugging states in DevTools
DevTools (the browser inspector) has a :hov panel that lets you emulate pseudo-states:
- Select an element in the Elements tab.
- Click the :hov button (in the Styles panel).
- Enable
:focus,:hover,:active, and so on. - The styles for that state become visible and editable.
:hover + :focus) to see which style overrides the other.Summary
| Topic | Key point |
|---|---|
<input> |
Single-line field; type defines the type (text, email, number…) |
<textarea> |
Multi-line field; font-family: inherit; limit the size |
<button> |
submit (send), reset (reset), button (JS) |
<label> |
Field caption; click → focus; linked by wrapping or for+id |
<form> |
Groups fields; action + method; submit event |
placeholder |
An example value (does not replace a label!) |
required |
Mandatory field (built-in validation) |
outline |
An outline on focus; does not affect dimensions; don’t remove it! |
:focus / :hover |
States for interactive elements; debug via :hov in DevTools |
cursor: pointer |
Pointer cursor on buttons (an arrow by default) |
:focus-visible |
Outline only during keyboard navigation (not on a mouse click) |
accent-color |
The color of checkbox, radio, range — in a single line of CSS |
autocomplete |
A hint to the browser for autofill ("name", "email", "tel") |