Forms

Introduction

Form related elements are among the most powerful HTML features, as they allow a web application to collect input from their users. Forms are used for a wide variety of purposes, such as login, registration, contact forms, search and more. Prior to modern JavaScript, forms were the primary means of creating dynamic and interactive content on the web. Today, forms are still a crucial part of the web, and you will find them on almost every website.

When thinking about form elements, keep a physical form in mind. A good example would be a driver’s license application, where the many pages require specific types of information to be entered into the right place. A web form is simply a digital recreation of a concept we are already familiar with.

The Form Element

The <form> element acts as a container, grouping related inputs together. On it’s own, a form element might not seem to do much at first. It does not provide any default styling, on first glance it may just seem to be a <div> with a special name. However, we can configure a form element in ways we cannot configure other elements.

Let’s look at a simple newsletter subscription form:

html
	<form>
	  <label for="name">Email:</label>
	  <input type="email" id="email" name="email" />
	  <button>Subscribe</button>
	</form>

If we press the button, the page will refresh. This is because the default behaviour of a form is to send the data that the user has entered into the inputs to a server. The page is in fact, not refreshing at all. What is happening here is that your HTML file is sending data to your local web server, and the local web server is replying to that request with the same page that you were looking at originally. This feels like a refresh, and we may refer to it as such, but the reality is more useful.

Action Attribute

Let’s modify our subscription form by setting an action attribute:

html
	<form action="/subscribe/thank-you.html">
	  <label for="name">Email:</label>
	  <input type="email" id="email" name="email" />
	  <button>Subscribe</button>
	</form>

Now that we have specified an action path, let’s try submitting the form again. This time, we are taken to a new page, thank-you.html. This is because we have told the form to send the data to a new page, and the server has responded by sending us that page.

Before modern JavaScript, the action attribute was the primary means of communicating with a server. The JavaScript requests we handle later in the program are exactly the same as the requests sent by a form submission in HTML.

Method Attribute

Let’s modify the form again by adding a method attribute:

html
	<form action="/subscribe/thank-you.html" method="GET">
	  <label for="name">Email:</label>
	  <input type="email" id="email" name="email" />
	  <button>Subscribe</button>
	</form>

Now, when we submit the form, we are taken to a new page, but the URL has changed. The URL now contains the data we entered into the form. The data is URL encoded, which is a type of formatting friendly to web servers. This behaviour will be more useful later on, but for now it’s worth being aware of it.

📄 DOCUMENTATION

Inputs

The <input> element is the primary means for collecting information directly from a user in HTML, alongside the <textarea> element. The <input> element is a self-closing element, meaning it does not have a closing tag. The <input> element has a number of attributes that can be used to configure it’s behaviour.

Types

Input types are used to specify what kind of data the input should collect. The default type is text, which is used for collecting short pieces of text, such as a name or phrase. It is crucial to select the correct type for the data you wish to collect, as this will affect the user experience. For example, if you use a number type for a phone number, the user will not be able to enter dashes or spaces, which will make the form difficult to use.

The most commonly used input types are:

  • text - Used for collecting short pieces of text, such as a name or phrase.
  • email - Used for collecting an email address.
  • password - Used for collecting a password. The text entered into a password input is hidden from view.
  • number - Used for collecting a number. The text entered into a number input is restricted to numbers only.
  • checkbox - Used for collecting a boolean (true/false) value. A checkbox can be checked or unchecked.
  • radio - Used for collecting a boolean value. A radio button can be selected or unselected. Radio buttons are grouped together by using the same name attribute.
  • search - Used for collecting a search query. The text entered into a search input is usually styled differently to a text input.
  • url - Used for collecting a URL. The text entered into a URL input is usually validated to ensure it is a valid URL.
  • date - Used for collecting a date. The text entered into a date input is usually validated to ensure it is a valid date.
  • file - Used for collecting a file. The text entered into a file input is usually validated to ensure it is a valid file.
  • color - Used for collecting a color. The text entered into a color input is usually validated to ensure it is a valid color.
  • range - Used for collecting a number within a range. The text entered into a range input is usually validated to ensure it is a valid number within the specified range.
  • tel - Used for collecting a telephone number. The text entered into a telephone input is usually validated to ensure it is a valid telephone number.

To read more about the additional input types available, please consult the MDN documentation below.

Name attribute

The name attribute is used to identify the input. This is important when the form is submitted, as the data will be sent to the server with the name of the input. The name attribute is also used to group radio buttons together.

html
	<input type="text" name="firstname" />

Please be aware that this attribute has a different purpose to the ID attribute. The name attribute is used to identify the input, whereas the id attribute is used to identify the element.

Labels

The <label> element is used to label an input. This is important for accessibility, as it allows screen readers to read the label to the user. The for attribute on the <label> element must match the id attribute on the <input> element.

Labels are essential for accessibility, and they provide a better user experience. When a user clicks on a label, the input is focused. This is useful for radio buttons and checkboxes, as it allows the user to select the input without having to click directly on the input.

Value attribute

You might have noticed new attribute on these <input> elements: the value attribute. You can also see that the value of the value attribute is set, like this: value="18-24".

What is the difference between the name and value attributes? The name helps to identify the <input> element, and the value attribute is used to retrieve the associated data of an <input> element.

In the case of a text type input field, it would be the user’s typed input. But as radio buttons do not have an associated default value, we must supply it. This is especially important for any input type that does not allow text input – the value must be set in advance.

We mentioned that the value attribute is used to retrieve data from an element but can also be used to set the data. Take this text type input element, <input value="Pre-filled text example">. In this case, the input field will be pre-filled with text.

Radio Buttons

Grouped radio buttons allow you to choose only one of the supplied options. On an HTML page, only one radio button may be chosen. If one button is chosen, the other radio buttons will deselect. For this reason, grouped radio buttons must share the same name. Here is an example:

html
	<input type="radio" name="age" value="18-24" id="age-range-1" />
	<label for="age-range-1">18-24</label>
	<input type="radio" name="age" value="25-35" id="age-range-2" checked />
	<label for="age-range-2">25-35</label>
	<input type="radio" name="age" value="36-50" id="age-range-3" />
	<label for="age-range-3">36-60</label>

Checkboxes

Checkboxes allow users to pick multiple (or no) options on the form. You will see that each checkbox’s name attribute is unique, unlike on radio buttons, where it was the same.

html
	<input type="checkbox" name="cats" value="cats" id="cats" />
	<label for="cats">Cats</label>
	<input type="checkbox" name="dogs" value="dogs" id="dogs" />
	<label for="dogs">Dogs</label>
	<input type="checkbox" name="dogs" value="hamster" id="hamster" checked />
	<label for="hamster">Hamster</label>
ℹ️ INFO

Note: you can check a checkbox or radio by default by adding the checked attribute. Read more about checkboxes here.

Select

If you want to create a menu of options list, you can use the select element. Each option inside the <select> should have a value set.

html
	<label for="cities">Choose a city:</label>
	<select name="cities" id="cities">
	  <option value="paris">Paris</option>
	  <option value="oslo">Oslo</option>
	  <option value="amsterdam">Amsterdam</option>
	  <option value="copenhagen">Copenhagen</option>
	</select>

Datalist

The <datalist> element is similar to a <select> in that it uses options for the user. The difference between the two is that with a select, the user must choose one of the available options, but with the datalist element it simply offers suggestions. Place your cursor inside the input to see the suggested options.

html
	<label for="pet-choice">Choose a pet:</label>
	<input list="pets" id="pet-choice" name="pet-choice" />
	
	<datalist id="pets">
	  <option value="Dog"></option>
	  <option value="Cat"></option>
	  <option value="Bird"></option>
	  <option value="Horse"></option>
	</datalist>

Textarea

To allow users to input multiple lines of text, as you would in a message, you can use the <textarea> element.

html
	<textarea id="message" name="message" rows="5" cols="30"></textarea>

The row and col attributes set how large the <textarea> element is, although this can cause issues in responsive design. In general, it’s best to control the sizing of <textarea> elements by using CSS.

Fieldsets

Fieldsets are a good way of organizing form data. The <fieldset> element may be wrapped around any number of input elements.

html
	<fieldset>
	  <legend>Personal information</legend>
	  <input type="text" name="firstname" />
	  <input type="text" name="lastname" />
	</fieldset>
Personal information

The <legend> tag supplies a caption for the <fieldset>, allowing the user to know what this group of inputs is about. More than one <fieldset> may be included in a form.

CSS Attribute Selectors

We will also be looking at another way of styling CSS – CSS attribute selectors. Attribute selectors allow us to define CSS rules by shared attributes. We will be using attribute selectors to style a form, which will illustrate how these may be used and how this will again make for more efficient CSS and less work spent on formatting elements that share attributes. The syntax for CSS attribute selectors is square braces containing the attribute, as follows:

css
	input[type='text'] {
	  padding: 10px;
	  width: 100%;
	}

This selector will affect any form input element with text type. As with other CSS selectors, careful planning will allow us to style multiple elements simultaneously.

Validation

Form validation is the process of ensuring that the data a user has entered into a web form matches the data that is expected. If we go back to an analogy with a physical paper form, an invalid form entry might be a field where a user has written a word in place of a phone number. Clearly the question asks for a phone number, however the user has ignored the instructions and entered information that will not work in the context of the form.

As developers we have the opportunity to validate the data that a user enters into a form before it has been sent. This would be like handing our paper form to an experienced lawyer, who can quickly tell us if the information we have entered is valid or not. Thankfully, unlike legal paperwork, HTML form validation is quick and easy to implement.

Required Attribute

In some forms, we may need to require that certain fields have been populated. For example, in a login form, we would need to require both the email and password fields. These fields are clearly not optional, however all form elements such as input are optional by default. In order to change this, we use the required attribute:

html
	<form action="/profile" id="login">
	  <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" required />
	  <button>Log in</button>
	</form>

If we try to submit this form without entering any data, we will see a message appear below the input fields. This message is provided by the browser in the user’s language, and it cannot be changed. This is a useful feature, as it means that we do not need to worry about translating our validation messages into different languages.

Min and Max Attributes

In some forms, we may need to require that certain fields have a minimum or maximum value. For example, an ecommerce store may have a minimum of 1 and a maximum of 10 for the quantity of an item. In order to enforce this, we can use the min and max attributes:

html
	<form action="/cart" id="add-to-cart">
	  <label for="quantity">Quantity:</label>
	  <input type="number" id="quantity" name="quantity" min="1" max="10" />
	  <button>View cart</button>
	</form>

Minlength and Maxlength Attributes

When dealing with text inputs, we may need to require that certain fields have a minimum or maximum length. For example, a username may have a minimum of 3 and a maximum of 20 characters. In order to enforce this, we can use the minlength and maxlength attributes:

html
	<form action="/login" id="register">
	  <label for="username">Username:</label>
	  <input type="text" id="username" name="username" minlength="3" maxlength="20" />
	  <button>Register</button>
	</form>

Pattern Attribute

In more advanced forms, we may need to require that certain fields match a specific pattern. For example, we may need to limit an email input to accept only a specific domain name. In order to enforce this, we can use the pattern attribute:

html
	<form action="/login" id="register">
	  <label for="email">Email:</label>
	  <input type="email" id="email" name="email" pattern=".*@noroff.no" />
	  <button>Register</button>
	</form>

This pattern attribute uses Regular Expressions or RegEx to match the user’s input with the pattern. Regular expressions are a powerful tool for matching patterns in text, and they are used in many programming languages. We will not be covering regular expressions in detail at this stage - but it is useful to be aware of this technology.

Title Attribute

When we use the pattern attribute, it is important to provide a title attribute. This is because the pattern attribute validation message is vague, and users are unlikely to understand the RegEx code within. Instead you can provide a title attribute, which will be displayed to the user if the pattern attribute validation fails:

html
	<form action="/login" id="register">
	  <label for="email">Email:</label>
	  <input
	    type="email"
	    id="email"
	    name="email"
	    pattern=".*@noroff.no"
	    title="Please enter a valid Noroff email address"
	  />
	  <button>Register</button>
	</form>

Novalidate Attribute

Occasionally while testing and developing forms, we find the need to disable validation. In order to achieve this, we can use the novalidate attribute:

html
	<form action="/login" id="register" novalidate>
	  <label for="email">Email:</label>
	  <input
	    type="email"
	    id="email"
	    name="email"
	    pattern=".*@noroff.no"
	    title="Please enter a valid Noroff email address"
	  />
	  <button>Register</button>
	</form>

Please note that this attribute should only be used during development, and it should be removed before the form is published, as it will not display an error in the case that a user adds text into a number field, for example.


Activities

💻 WATCH

This tutorial video on using forms. (10m 21s)


Lesson Task

Brief

There are practice questions in the master branch of this repo.

Attempt the answers before checking them against the answers in the answers branch of the repo.