Definition of the <form> tag
The <form> tag is one of the most fundamental elements in HTML. It allows you to create an interactive form that collects data entered by the user and sends it to a server for processing. Without it, no registration, no login, no online payment would be possible. It is truly the bridge between the user and the server.
If you want to fully master HTML forms and all the subtleties of the language, we recommend following our complete HTML course which covers this topic in depth.
An HTML form acts as a container for different interactive elements: text fields (<input>), dropdown menus (<select>), text areas (<textarea>), buttons (<button>), checkboxes, radio buttons, and many more. When the user submits the form, the data contained in these elements is sent to the server using the specified HTTP method.
Basic syntax
The syntax of the <form> tag is relatively simple. It opens with <form> and closes with </form>. All form elements must be placed between these two tags.
<form action="/processing" method="post">
<label for="name">Your name:</label>
<input type="text" id="name" name="name">
<label for="email">Your email:</label>
<input type="email" id="email" name="email">
<button type="submit">Submit</button>
</form>In this example, we have a simple form with two fields and a submit button. The action attribute indicates the URL to which the data will be sent, and the method attribute specifies the HTTP method used.
Essential attributes of <form>
The <form> tag has many attributes that control its behavior. Understanding these attributes is essential for creating functional and secure forms.
The action attribute
The action attribute defines the URL to which the form data will be sent upon submission. If this attribute is omitted, the data is sent to the current page URL.
<!-- Sending to a specific URL -->
<form action="https://example.com/api/registration">
...
</form>
<!-- Sending to the current page (action omitted) -->
<form>
...
</form>
<!-- Sending to a relative path -->
<form action="/users/create">
...
</form>
The method attribute
The method attribute specifies the HTTP method used to send the data. The two main values are GET and POST.
| Method | Description | Use case |
|---|---|---|
GET | Data is appended to the URL as query parameters | Search, filters, non-sensitive data |
POST | Data is sent in the body of the HTTP request | Registration, login, file uploads, sensitive data |
<!-- Search form with GET -->
<form action="/search" method="get">
<input type="text" name="q" placeholder="Search...">
<button type="submit">Search</button>
</form>
<!-- The resulting URL will be: /search?q=keyword -->
<!-- Login form with POST -->
<form action="/login" method="post">
<input type="text" name="username">
<input type="password" name="password">
<button type="submit">Log in</button>
</form>Never use the GET method to send sensitive data such as passwords. GET parameters are visible in the URL, in the browser history, and in server logs.
The enctype attribute
The enctype attribute defines the encoding type used when sending data. It is particularly important when you need to upload files.
| Value | Description |
|---|---|
application/x-www-form-urlencoded | Default value. Encodes special characters. |
multipart/form-data | Required for file uploads. Does not modify data encoding. |
text/plain | Sends data as plain text. Rarely used. |
<!-- File upload form -->
<form action="/upload" method="post" enctype="multipart/form-data">
<label for="avatar">Choose a profile picture:</label>
<input type="file" id="avatar" name="avatar" accept="image/*">
<button type="submit">Upload</button>
</form>If you forget to add enctype="multipart/form-data" on a form containing a file type field, the file will not be correctly transmitted to the server.
Other important attributes
Here are other attributes you can use on the <form> tag:
| Attribute | Description |
|---|---|
target | Specifies where to display the response (_self, _blank, _parent, _top) |
autocomplete | Enables (on) or disables (off) browser autocomplete |
novalidate | Disables native browser validation on submission |
name | Gives the form a name to reference it in JavaScript |
rel | Specifies the relationship between the current document and the target |
<!-- Form without native validation, with autocomplete disabled -->
<form action="/registration" method="post" novalidate autocomplete="off">
<input type="email" name="email" required>
<input type="password" name="password" minlength="8" required>
<button type="submit">Sign up</button>
</form>
Practical form examples
Let's now look at concrete examples of forms that you will frequently encounter in your web projects.
Complete registration form
Here is a typical registration form using different field types, <label> for accessibility, and a <fieldset> to logically group fields:
<form action="/api/registration" method="post">
<fieldset>
<legend>Personal information</legend>
<label for="firstname">First name:</label>
<input type="text" id="firstname" name="firstname" required>
<label for="lastname">Last name:</label>
<input type="text" id="lastname" name="lastname" required>
<label for="birthdate">Date of birth:</label>
<input type="date" id="birthdate" name="birthdate">
</fieldset>
<fieldset>
<legend>Login credentials</legend>
<label for="email">Email:</label>
<input type="email" id="email" name="email" required>
<label for="password">Password:</label>
<input type="password" id="password" name="password" minlength="8" required>
<label for="password-confirm">Confirm password:</label>
<input type="password" id="password-confirm" name="password_confirm" minlength="8" required>
</fieldset>
<label>
<input type="checkbox" name="terms" required>
I accept the terms and conditions
</label>
<button type="submit">Create my account</button>
</form>
Contact form
A contact form is another very common use case. It combines standard text fields with a larger text area for the message:
<form action="/contact" method="post">
<label for="contact-name">Your name:</label>
<input type="text" id="contact-name" name="name" required>
<label for="contact-email">Your email:</label>
<input type="email" id="contact-email" name="email" required>
<label for="contact-subject">Subject:</label>
<select id="contact-subject" name="subject">
<option value="">-- Choose a subject --</option>
<option value="support">Technical support</option>
<option value="sales">Sales inquiry</option>
<option value="other">Other</option>
</select>
<label for="contact-message">Your message:</label>
<textarea id="contact-message" name="message" rows="6" required></textarea>
<button type="submit">Send message</button>
</form>
Search form
Search forms are generally short and use the GET method, because search terms are not sensitive and it is useful to be able to share the results URL:
<form action="/search" method="get" role="search">
<label for="search">Search:</label>
<input type="search" id="search" name="q" placeholder="Type your search..." required>
<button type="submit">Search</button>
</form>The role="search" attribute improves accessibility by indicating to assistive technologies that this form is a search form.
Form validation
HTML5 introduced a very powerful native validation system that allows you to check user-entered data before it is even sent to the server. This client-side validation improves the user experience, but should never replace server-side validation.
Validation attributes
Here are the main validation attributes available on form elements:
| Attribute | Description | Example |
|---|---|---|
required | The field must be filled in | <input required> |
minlength | Minimum number of characters | <input minlength="3"> |
maxlength | Maximum number of characters | <input maxlength="50"> |
min | Minimum numeric value | <input type="number" min="0"> |
max | Maximum numeric value | <input type="number" max="100"> |
pattern | Regular expression to match | <input pattern="[A-Za-z]{3,}"> |
type | Automatic validation based on type | <input type="email"> |
<form action="/validate" method="post">
<!-- Required field with minimum length -->
<label for="username">Username (3-20 characters):</label>
<input type="text" id="username" name="username"
required minlength="3" maxlength="20"
pattern="[a-zA-Z0-9_]+"
title="Only letters, numbers, and underscores">
<!-- Email field with automatic validation -->
<label for="email">Email:</label>
<input type="email" id="email" name="email" required>
<!-- Numeric field with limits -->
<label for="age">Age (18-120):</label>
<input type="number" id="age" name="age" min="18" max="120">
<!-- Phone field with pattern -->
<label for="tel">Phone:</label>
<input type="tel" id="tel" name="phone"
pattern="[0-9]{10}"
title="Enter a 10-digit number">
<button type="submit">Validate</button>
</form>Client-side validation (HTML or JavaScript) should never be your only line of defense. A malicious user can easily bypass this validation. Always validate data on the server side as well.
Form accessibility
Accessibility is a crucial aspect of form design. A poorly structured form can be completely unusable for people using assistive technologies such as screen readers.
Essential accessibility rules
Here are the best practices to follow systematically:
- Always associate a <label> with each field: use the
forattribute on the<label>that matches the field'sid. - Use <fieldset> and
<legend>: group logically related fields (for example, radio buttons for the same choice). - Provide clear error messages: clearly indicate what needs to be corrected.
- Use ARIA attributes when necessary:
aria-describedby,aria-required,aria-invalid. - Ensure keyboard navigation: the user must be able to fill out the entire form using the Tab key.
<form action="/registration" method="post">
<!-- Correctly associated label -->
<label for="user-email">Email address:</label>
<input type="email" id="user-email" name="email"
required aria-describedby="email-help">
<span id="email-help">Example: user@domain.com</span>
<!-- Radio button group with fieldset -->
<fieldset>
<legend>Your HTML level:</legend>
<label>
<input type="radio" name="level" value="beginner">
Beginner
</label>
<label>
<input type="radio" name="level" value="intermediate">
Intermediate
</label>
<label>
<input type="radio" name="level" value="advanced">
Advanced
</label>
</fieldset>
<button type="submit">Submit</button>
</form>
Styling a form with CSS
HTML forms are notoriously difficult to style consistently across browsers. Here is an example of basic CSS to give your forms a professional look:
form {
max-width: 500px;
margin: 0 auto;
padding: 2rem;
}
label {
display: block;
margin-bottom: 0.5rem;
font-weight: bold;
}
input[type="text"],
input[type="email"],
input[type="password"],
textarea,
select {
width: 100%;
padding: 0.75rem;
margin-bottom: 1rem;
border: 1px solid #ccc;
border-radius: 4px;
font-size: 1rem;
box-sizing: border-box;
}
input:focus,
textarea:focus,
select:focus {
outline: none;
border-color: #4a90d9;
box-shadow: 0 0 0 3px rgba(74, 144, 217, 0.25);
}
input:invalid:not(:placeholder-shown) {
border-color: #e74c3c;
}
input:valid:not(:placeholder-shown) {
border-color: #2ecc71;
}
button[type="submit"] {
background-color: #4a90d9;
color: white;
padding: 0.75rem 2rem;
border: none;
border-radius: 4px;
font-size: 1rem;
cursor: pointer;
}
button[type="submit"]:hover {
background-color: #357abd;
}This CSS uses the :focus, :valid, and :invalid pseudo-classes to provide visual feedback to the user. The :placeholder-shown pseudo-class prevents fields from being marked as invalid before the user has even started filling them in.
Best practices
To create efficient, accessible, and secure forms, here are the best practices you should systematically apply:
- Always use the
POSTmethod for sensitive data (passwords, personal information). - Add a
nameattribute to each form field, as this name will be used as the key when sending data to the server. - Use the right
inputtypes:email,tel,url,number,date, etc. This enables native validation and displays the correct keyboard on mobile. - Don't forget the
enctype="multipart/form-data"attribute when your form contains file input fields. - Favor HTML semantics: use <fieldset>,
<legend>, <label>, <datalist>, and appropriate input types rather than rebuilding everything with <div>. - Implement CSRF protection (Cross-Site Request Forgery) on the server side for your sensitive forms.
- Add appropriate
autocompleteattributes on each field to improve the user experience. - Test your forms with the keyboard: make sure the tab order is logical and the form is entirely navigable without a mouse.
Interaction with JavaScript
The <form> tag interacts closely with JavaScript to offer advanced user experiences. Here is how to intercept a form submission:
const form = document.querySelector('form');
form.addEventListener('submit', function(event) {
// Prevent the default form submission
event.preventDefault();
// Retrieve the form data
const data = new FormData(form);
// Asynchronous submission with fetch
fetch('/api/registration', {
method: 'POST',
body: data
})
.then(response => response.json())
.then(result => {
console.log('Success:', result);
})
.catch(error => {
console.error('Error:', error);
});
});The FormData object is extremely convenient: it automatically collects all form data (including files) and formats it correctly for sending. This approach with fetch() is now the recommended method for submitting forms asynchronously, without page reload.
Frequently asked questions
What is the difference between GET and POST methods in a form?
The GET method appends form data directly to the URL as parameters (for example /search?q=html). It is visible, limited in size, and suitable for searches or filters. The POST method sends data in the body of the HTTP request, so it is invisible in the URL. Use POST for sensitive data, files, or large volumes of data.
Can you nest forms in HTML?
No, it is forbidden to nest <form> tags inside each other according to the HTML specification. If you need multiple actions on the same page, you can use the form attribute on <input> or <button> elements to associate them with a specific form without them being physically inside it.
How do you submit a form without reloading the page?
To submit a form without reloading, you need to use JavaScript. Intercept the submit event with addEventListener, call event.preventDefault() to prevent the default behavior, then use the fetch() API or XMLHttpRequest to send the data asynchronously (AJAX). The FormData object greatly simplifies collecting form data.
How can I learn to create complete HTML forms?
Mastering HTML forms requires practice and a good understanding of the various elements available (<input>, <select>, <textarea>, <fieldset>, <button>, <datalist>, etc.). To progress efficiently, we recommend following our HTML course on Believemy, which will guide you step by step through creating accessible, secure, and professional forms, with hands-on practical exercises.