Create a HTML form
In this tutorial, you will create a simple <form> using plain HTML and CSS and deploy it to Cloudflare Pages. While doing so, you will learn about some of the HTML form attributes and how to collect submitted data within a Worker.
This tutorial will make heavy use of Cloudflare Pages and its Workers integration. Refer to the Get started guide guide to familiarize yourself with the platform.
On the web, forms are a common point of interaction between the user and the web document. They allow a user to enter data and, generally, submit their data to a server. A form is comprised of at least one form input, which can vary from text fields to dropdowns to checkboxes and more.
Each input should be named – using the name ↗ attribute – so that the input's value has an identifiable name when received by the server. Additionally, with the advancement of HTML5, form elements may declare additional attributes to opt into automatic form validation. The available validations vary by input type; for example, a text input that accepts emails (via type=email ↗) can ensure that the value looks like a valid email address, a number input (via type=number) will only accept integers or decimal values (if allowed), and generic text inputs can define a custom pattern ↗ to allow. However, all inputs can declare whether or not a value is required ↗.
Below is an example HTML5 form with a few inputs and their validation rules defined:
<form method="POST" action="/api/submit"> <input type="text" name="fullname" pattern="[A-Za-z]+" required /> <input type="email" name="email" required /> <input type="number" name="age" min="18" required />
<button type="submit">Submit</button></form>If an HTML5 form has validation rules defined, browsers will automatically check all rules when the user attempts to submit the form. Should there be any errors, the submission is prevented and the browser displays the error message(s) to the user for correction. The <form> will only POST data to the /submit endpoint when there are no outstanding validation errors. This entire process is native to HTML5 and only requires the appropriate form and input attributes to exist — no JavaScript is required.
Form elements may also have a <label> ↗ element associated with them, allowing you to clearly describe each input. This is great for visual clarity, of course, but it also allows for more accessible user experiences since the HTML markup is more well-defined. Assistive technologies directly benefit from this; for example, screen readers can announce which <input> is focused. And when a <label> is clicked, its assigned form input is focused instead, increasing the activation area for the input.
To enable this, you must create a <label> element for each input and assign each <input> element and unique id attribute value. The <label> must also possess a for ↗ attribute that reflects its input's unique id value. Amending the previous snippet should produce the following:
<form method="POST" action="/api/submit"> <label for="i-fullname">Full Name</label> <input id="i-fullname" type="text" name="fullname" pattern="[A-Za-z]+" required />
<label for="i-email">Email Address</label> <input id="i-email" type="email" name="email" required />
<label for="i-age">Your Age</label> <input id="i-age" type="number" name="age" min="18" required />
<button type="submit">Submit</button></form>When this <form> is submitted with valid data, its data contents are sent to the server. You may customize how and where this data is sent by declaring attributes on the form itself. If you do not provide these details, the <form> will GET the data to the current URL address, which is rarely the desired behavior. To fix this, at minimum, you need to define an action ↗ attribute with the target URL address, but declaring a method ↗ is often recommended too, even if you are redeclaring the default GET value.
By default, HTML forms send their contents in the application/x-www-form-urlencoded MIME type. This value will be reflected in the Content-Type HTTP header, which the receiving server must read to determine how to parse the data contents. You may customize the MIME type through the enctype ↗ attribute. For example, to accept files (via type=file), you must change the enctype to the multipart/form-data value:
<form method="POST" action="/api/submit" enctype="multipart/form-data"> <label for="i-fullname">Full Name</label> <input id="i-fullname" type="text" name="fullname" pattern="[A-Za-z]+" required />
<label for="i-email">Email Address</label> <input id="i-email" type="email" name="email" required />
<label for="i-age">Your Age</label> <input id="i-age" type="number" name="age" min="18" required />
<label for="i-avatar">Profile Picture</label> <input id="i-avatar" type="file" name="avatar" required />
<button type="submit">Submit</button></form>Because the enctype changed, the browser changes how it sends data to the server too. The Content-Type HTTP header will reflect the new approach and the HTTP request's body will conform to the new MIME type. The receiving server must accommodate the new format and adjust its request parsing method.
The rest of this tutorial will focus on building an HTML form on Pages, including a Worker to receive and parse the form submissions.
To begin, create a new GitHub repository ↗. Then create a new local directory on your machine, initialize git, and attach the GitHub location as a remote destination:
# create new directorymkdir new-project# enter new directorycd new-project# initialize gitgit init# attach remotegit remote add origin git@github.com:<username>/<repo>.git# change default branch namegit branch -M mainYou may now begin working in the new-project directory you created.
The form for this example is fairly straightforward. It includes an array of different input types, including checkboxes for selecting multiple values. The form also does not include any validations so that you may see how empty and/or missing values are interpreted on the server.
You will only be using plain HTML for this example project. You may use your preferred JavaScript framework, but raw languages have been chosen for simplicity and familiarity – all frameworks are abstracting and/or producing a similar result.
Create a public/index.html in your project directory. All front-end assets will exist within this public directory and this index.html file will serve as the home page for the website.
Copy and paste the following content into your public/index.html file:
<html lang="en"> <head> <meta charset="utf8" /> <title>Form Demo</title> <meta name="viewport" content="width=device-width,initial-scale=1" /> </head> <body> <form method="POST" action="/api/submit"> <div class="input"> <label for="name">Full Name</label> <input id="name" name="name" type="text" /> </div>
<div class="input"> <label for="email">Email Address</label> <input id="email" name="email" type="email" /> </div>
<div class="input"> <label for="referers">How did you hear about us?</label> <select id="referers" name="referers"> <option hidden disabled selected value></option> <option value="Facebook">Facebook</option> <option value="Twitter">Twitter</option> <option value="Google">Google</option> <option value="Bing">Bing</option> <option value="Friends">Friends</option> </select> </div>
<div class="checklist"> <label>What are your favorite movies?</label> <ul> <li> <input id="m1" type="checkbox" name="movies" value="Space Jam" /> <label for="m1">Space Jam</label> </li> <li> <input id="m2" type="checkbox" name="movies" value="Little Rascals" /> <label for="m2">Little Rascals</label> </li> <li> <input id="m3" type="checkbox" name="movies" value="Frozen" /> <label for="m3">Frozen</label> </li> <li> <input id="m4" type="checkbox" name="movies" value="Home Alone" /> <label for="m4">Home Alone</label> </li> </ul> </div>
<button type="submit">Submit</button> </form> </body></html>