HTML forms: basic form building blocks

Home / Everything About / Everything About Forms / HTML forms: basic form building blocks

When you build a form, you use frameworks or form builders. But under the hood, they all use HTML forms. If you understand how HTML forms work, you understand everything else. You are not dependent on any tool or framework. You know the fundamentals.

This article covers the HTML form element, input types, labels, validation, and how forms actually submit. No frameworks. No libraries. Just HTML and the principles that everything else is built on.

The HTML form element

A form is an HTML element that wraps form fields and sends their data somewhere. The basic structure is:

<form action="/submit" method="POST">

<input type="text" name="email">

<button type="submit">Send</button>

</form>

Three attributes matter. The action attribute tells the form where to send data. "/submit" means post to the /submit endpoint on your server. If action is blank, the form submits to the current page. The method attribute tells the form how the data travels. POST sends data in the request body (secure, hidden from the URL). GET appends data to the URL (insecure for sensitive data, useful for search queries). The enctype attribute is only needed for file uploads. Set enctype="multipart/form-data" when your form has a file input field.

Everything inside the form tags is part of the submission. When the user clicks a submit button, the browser collects all the named fields and sends them to the action URL using the specified method.

Input types and what they do

text

<input type="text" name="first_name">

A single-line text field. The browser shows a basic text box. No validation. Any character is allowed.

email

<input type="email" name="email">

A field for email addresses. On desktop, it looks like a text field. On mobile, the browser shows an email keyboard. On submit, the browser checks that the value looks like an email (contains an @). Basic validation only.

password

<input type="password" name="password">

Text that is hidden as dots or asterisks as you type. The value still transmits in plain text, so always use HTTPS on forms with password fields.

number

<input type="number" name="age">

On desktop, a text field that accepts only numbers. On mobile, the browser shows a numeric keyboard. The browser prevents non-numeric input.

date

<input type="date" name="birth_date">

A date picker. On supported browsers and devices, clicking the field opens a calendar. The value is formatted as YYYY-MM-DD.

checkbox

<input type="checkbox" name="agree" value="yes">

A box that toggles on and off. If checked, the field's value is sent on submit. If unchecked, the field is not sent at all.

radio

<input type="radio" name="plan" value="starter"> Starter

<input type="radio" name="plan" value="pro"> Pro

Multiple radio buttons with the same name act as a group. Only one can be selected at a time. The value of the selected one is sent on submit.

select (dropdown)

<select name="country">

<option value="us">United States</option>

<option value="ca">Canada</option>

</select>

A dropdown menu. The value of the selected option is sent on submit.

textarea

<textarea name="message"></textarea>

A multi-line text field. Users can type paragraphs. The value includes line breaks.

file

<input type="file" name="resume">

A button that opens the device's file picker. The selected file is sent to the server. Requires enctype="multipart/form-data" on the form element.

hidden

<input type="hidden" name="user_id" value="12345">

A field that is not displayed but is sent on submit. Useful for tracking data that should be included but the user should not change.

Labels and accessibility

Always pair input fields with labels.

<label for="email">Email address</label>

<input type="email" id="email" name="email">

The for attribute on the label must match the id on the input. When you do this correctly:

Screen readers announce the label and field together, clicking the label focuses the input field, and mobile users get a larger touch target.

Never skip labels. If you need to hide a label visually, use CSS to hide it but keep it in the HTML. This is called a "visually hidden" label.

Grouping related fields

For related fields, use fieldset and legend.

<fieldset>

<legend>Shipping address</legend>

<input type="text" name="street">

<input type="text" name="city">

</fieldset>

The legend element announces the group to screen readers. Fieldsets help organize radio buttons and checkboxes visually and semantically.

Form submission and HTTP methods

When the user clicks the submit button, the browser collects all named fields, encodes the data (application/x-www-form-urlencoded by default), sends an HTTP request to the action URL with the method (POST or GET), and waits for a response.

The server receives the request and can process the data. The data arrives as key-value pairs. If the form method is POST and the action is "/submit", the request appears as follows. POST /submit HTTP/1.1 with Content-Type set to application/x-www-form-urlencoded, then the data appears as email=user@example.com&name=John.

The server parses this data and responds. If the response is a page, the browser loads it. If the response is a redirect, the browser navigates to the new URL.

Client-side validation

HTML has built-in validation attributes. The browser checks these before sending the form.

required

<input type="text" name="email" required>

The field must have a value. If left blank, the form will not submit and the browser shows an error.

minlength and maxlength

<input type="password" name="password" minlength="8" maxlength="128">

The value must be between the specified character counts.

min and max

<input type="number" name="age" min="18" max="120">

For number fields, the value must be within the range.

pattern

<input type="text" name="zip_code" pattern="[0-9]{5}">

A regular expression that the value must match. A five-digit zip code matches [0-9]{5}.

Client-side validation is a convenience for users. It prevents them from submitting invalid data and seeing an error from the server. But never rely on client-side validation for security. Always validate on the server too.

Understanding the difference between type="submit" and type="button"

<button type="submit">Send</button>

<button type="button">Save</button>

A button with type="submit" submits the form when clicked. A button with type="button" does nothing by default. Use type="button" when you want to attach JavaScript event handlers.

Many developers use <button> without specifying type. This defaults to type="submit", which is usually what you want. But be explicit to avoid surprises.

Why you should understand HTML forms

If you use React, Vue, or Angular, you are building on top of HTML forms. Frameworks abstract the details, but the underlying principles are the same. A form still submits to an endpoint. Validation still needs to happen. The server still needs to handle the data.

When something breaks in your form handling, understanding HTML helps you debug. You know where the data comes from, how it gets encoded, and what the server should receive. This is the foundation.

Most modern web apps do not use traditional form submission anymore. They use JavaScript to intercept the form, validate it, and send data via fetch or axios. But knowing the HTML way first makes those patterns make sense.

How WEMASY form builder uses these principles

Under the hood, WEMASY's form builder generates accessible HTML forms using these same elements. Labels are paired with inputs. Validation is handled both client-side and server-side. Form data is submitted securely. If you export or customize a WEMASY form, you are working with HTML forms built on these fundamentals.

See the WEMASY pricing page for details on form features and customization options.

Frequently asked questions

Should I use GET or POST for my form submission?

Is client-side validation enough or do I need server-side validation too?

How do I send a form with JavaScript instead of the default submission?

What is the difference between form data and JSON?

Why should I use label elements instead of just putting text next to inputs?

Do I need to worry about CSRF protection on forms?