Now that our simple portfolio page contains a table of our previous employments, the only thing left to do is add a way for people to contact us; after all, there is no point wowing prospective employers with our skills and experience if they can not get in touch with us.
So far, everything that we have added to our page has been to provide the visitor with information, as doing so is often the primary purpose of a HTML document1. Sometimes, however, you need the information to flow in the other direction, to collect information from the user; and forms in HTML are how you do that. Just like their paper equivalents, they consist of a series of fields that visitors fill in, which when submitted can be read and processed.
Here, we're using a form to allow visitors to send us a message, but they can be used for almost anything where you need to collect data from the visitor; think website logins, getting driving directions, online checkouts, web search engines etc.
To create a form in HTML we use the
form element, which then accepts a number of different types of elements as children which act as the fields of the form. When a visitor fills in these fields and submits the form, any data they have entered will be sent to whatever url is specified in the form's
action attribute. HTML itself can not do anything with the information that users submit, it can only send it to somewhere else for processing.
This can be very confusing for beginners, as doing anything with the data that users have submitted using your forms requires learning a whole new programming language. However, by decoupling the collection of data from the processing of it, it grants us tremendous flexibility; we can decide whether we want to use that data to log a user in to our website, send them a set of tickets for a particular concert, add their observations to an amateur scientific project, or simple email us a copy of what they entered.
Learning one of these so called 'backend' languages is out of the scope of this book, but fortunately there are services that can handle ths for us, and we will be using one of these for our simple contact form. Before we start looking at processing the data from a form, however, we first need to look at collecting it.
As alluded to earlier, a
form element can accept several types of elements as children to act as its fields. The most common of these is the
input element, which has a
type attribute to define what type of data we are expecting, and a
name attribute to identify the field when we come to process the data.
Users fill out the form by focusing each input in turn to fill them out, and then submitting the form when they have completed it. Focusing an element is often performed by clicking or touching into it with a mouse our touchscreen, but can also be achieved using the
tab key on a keyboard to move between them.
An extremely simple form could be created like so:
<form action="https://example.com"> <input type="text" name="name" /> <input type="submit" value="Submit Form" /> </form>
Here we have defined a simple form with two
inputs. The first is a text field called name, and the second acts as a button to allow submitting the form. When rendered in a browser it will look something like this:
When a user clicks (or touches, or presses enter on their keyboard, or any other way of interacting with it) on the button any data they have entered into the name input will be sent to
https://example.com. What is done with the data when it gets there will be entirely dependant on what use the form is trying to serve.
Our single field form is already completely functional, but it does not convey to the user what information we are expecting them to give us. For that purpose, HTML has the
label element. These accept a
for attribute, which contains the
id of the element they are associated with, and any content they are given will become the label. In HTML, the
id attribute can be applied to any element, and should be a unique identifier for that specific element; normally we don't have a use for these, but in particular circumstances (such as adding a label here) we may need to add one.
We could add a label to our text
input like so:
<form action="https://example.com"> <label for="name">Your name</label> <input type="text" name="name" id="name" /> <input type="submit" value="Submit Form" /> </form>
and when rendered by the browser it would look like this:
Labels are extremely useful, as the text of a
label associated with an
input is read out to screen-reader users when they focus on the input. Also, if users click or touch the label it will automatically move focus to the input, ready to enter data.
Other field types
So far, we have only seen a plain text field, but HTML supports many other types of inputs. The
input element itself supports many different values for its
type attribute, including:
file etc. By specifying the correct type of input the browser will change how they are presented to the user (such as a date picker for the date field, or increment and decrement arrows on numbers) and will perform some basic validation on the inputs to ensure the user has entered the right kind of data (checking that a valid email address was entered, or only a number into a number field for example).
In addition to the
input element, there are also a few other types of element that can be used as fields. An example of this is the
select element, which has one or more
option elements as children; the contents of which provide the items in a drop-down list. We could create a select field for booking tickets to events like this:
<form action="/booking"> <label for="ticket-type">Type of ticket:</label> <select name="ticket-type" id ="ticket-type"> <option value="standing">Standing</option> <option value="box">Box</option> <option value="backstage">Backstage Pass</option> </select> </form>
Ordinarily, the value of a field when the form is submitted will be whatever data the user entered, but in the case of a
select element it will be the
value attribute of the selected
option. When rendered by the browser the above form would appear like this:
Type of ticket: Standing Box Backstage Pass
The text input used in our first example form only works for a single line of text, such as a name or message subject. For multi-line fields we instead use a
textarea. Just like an
textarea should have an associated
label and can have the number of allowed characters restricted using a
maxlength attribute. Unlike
inputs, however, a
textarea is not self-closing and must have a closing tag like so:
There are many other possible children allowed for a
form element that I have not covered here. A good reference for all of them, and the attributes they can accept, is on MDN.
Building a contact form
Now that we know how to create a form in HTMl, we are ready to add one to our page. For processing any data submitted to the form I used an online service called getform.io2. It is a paid service, but at the time of writing they have a free plan where you can add a single form and accept up to 50 submissions a month.
Generally, any external service must be thoroughly checked for security and how they handle your data, but for the purposes of testing it should be fine. If you happen to be experienced in any of the backend languages that can be used to process form data feel free to write that part yourself.
First of all, let's add the contact form to our portfolio page. Insert the following lines after the last
section and before the closing
<section> <h2>Get in touch</h2> <form action="https://getform.io/f/921c2467-5918-4ddd-88e5-ee8f7674034d" method="POST"> <div> <label for="name">Your Name:</label> <input type="text" name="name" id="name" /> </div> <div> <label for="email">Your Email:</label> <input type="email" name="email" id="email" required /> </div> <div> <label for="subject">Subject:</label> <input type="text" name="subject" id="subject" /> </div> <div> <label for="message">Message:</label> <textarea name="message" id="message" required></textarea> </div> <div> <button type="submit">Send</button> </div> </form> </section>
As before we have added a new
section element to hold our contact form. The
form itself has an action url pointing to whatever page will process our data. In the case of the example this is my test form on getform.io, but you will need to replace it with the url that is unique to your form. The
method="POST" attribute is indicating that this form's data should be sent with a
POST, rather than a
GET, request. The differences between the two are a little complex to worry about for now3 but, essentially, a
POST request is more secure; what you want when sending any form of personal information.
labels are both inline elements, and I have wrapped them in simple
div tags to separate them out. A
div is a semantically meaningless block level element that can be used to group elements when no other specific elements are appropriate.
The only other thing which is new in this example is the addition of the
required attribute to the email and message fields. Any fields that are marked as
required will prevent the user from submitting the form if they are empty and the browser will display a message indicating that they should be filled in; this is a little unusual as it does not take a value, but is an empty attribute. Please use these judiciously as they can be confusing to users, but insisting that a contact form must have a message and way of getting back in touch with the user seems reasonable.
The only other thing to do now is to setup the form processing. If you decide to use the same service as myself they have some good documentation on how to do this. Essentially, all you want to do is create a new form, copy the action url into the
action attribute of the
form on your portfolio page, and setup an email notification. Their documentation covers all of this.
If you decide you would like to process the data in another way feel free to do so.
As a final change I have also added
tel: links to the page's footer in case the form does not work, or users would prefer to contact us directly. Do this at your discretion, as bots can sometimes get hold of an email and send spam emails. It is often a good idea to add additional contact methods to a site, however, as not everyone uses email or finds filling in forms convenient.
The updated footer code is below:
<footer> <p>Copyright © Catwaladr Caractapus</p> <h3>Contact</h3> <ul> <li>Email: <a href="mailto:email@example.com">firstname.lastname@example.org</a></li> <li>Telephone: <a href="tel:07000000000">07000 000 000</a></li> </ul> </footer>
Now that the contact form has been added, the HTML for our basic portfolio page is complete. If you run into any issues, or just want to see what my version looks like, you can get the page's source code on github.
We've covered a huge amount over the last nine chapters, and if there is something you are still unsure of please do go back and read it again. The best way to learn is by doing, so do try putting your new skills to the test by making some other webpages. Perhaps you could try making a basic news article, or recipe for cooking your favourite dish?
The main thing to writing good HTML is using appropriate elements for the content. As there are more elements available than can be comfortably remembered a good reference is essential, and perhaps the best is the Mozilla Developer Network; they also have some excellent tutorials that explain many of the concepts we have covered in greater depth.
In the next section we will look at CSS. Another language of the web that allows us to change the visual display of web pages.
- Think about how many pages consist of things to read / watch, versus those asking you to enter information.
- I am in no way affiliated with this company. Their service just seemed like the easiest way of allowing you to see your form was working without teaching you a whole different language.
- If you are interested you can read more about it here.
This is a chapter from my Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License book, Building Websites for Beginners. You can read everything that I have written so far on the book website, and can see the source code on github.
Top comments (4)
This chapter doesn't seem to have rendered quite so well when porting it across, as the form elements have been stripped out. That makes a lot of sense from a security point of view. If are wondering what the form examples should really look like check out the original post where they work correctly.
Great insight. Hopefully, the author will have a chance to look 👀 into this. Welcome to the community! 🤓
There is a typo in the link, provided for the form.. this took me some time to realize
Thank you for catching that, I'll update it now.