Building Forms

Lecture notes: form elements, field styling, validation, label, outline, :focus and :hover states

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
If type is not specified, it defaults to text. A reference for all types: MDN — <input>.

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">
A correct 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;
}
Always add 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.
Set 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;
}
Buttons look different across browsers. Always reset border, background, font-family and style them from scratch.
Add 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">
Clicking a <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
Order of checks: first required (whether it is empty), then type (format), then pattern and other constraints.
Built-in validation is only basic protection. Serious projects need additional checks on the server (backend).

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;
}
Never remove the 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:

  1. Select an element in the Elements tab.
  2. Click the :hov button (in the Styles panel).
  3. Enable :focus, :hover, :active, and so on.
  4. The styles for that state become visible and editable.
You can enable several states at once (for example, :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")

Vitalii Kaplia

Digital Product Engineer & Web Solutions Architect, Founder of KAPLIA.PRO

I got interested in programming back in 1997 — my first acquaintance with the future profession came through Visual Basic.…

More about author

A digital product engineer and web solutions architect

Free consultation + cost calculation

Let’s discuss your project?

Free consultation + cost calculation

More interesting articles

Customer login

This site uses cookies

We use cookies to personalize content and ads, provide social media features, and analyze our traffic. We also share information about your use of our website with our social media, advertising, and analytics partners, who may combine it with other information you have provided to them or collected when you use their services. By continuing to use our site, you consent to our use of cookies and accept our Privacy Policy and Terms of Use.

Virtual assistant
Hi! I'm the KAPLIA.PRO virtual assistant! I can tell you about our services, portfolio projects, ballpark pricing, and how we work — from websites and eCommerce to web apps, CRMs, bots, and AI agents. Ask away!

By continuing with the AI assistant, I agree to the site’s terms of use and privacy policy.

AI assistant may make mistakes in responses