Did you ever create a HTML form, just to discover that it doesn't send what and where you want?
That the data you send cannot be properly used or that you don't get what you expected?
When you cobble together a form, but never understand the real meaning of all the different enctypes and methods, you will always just be able to only assume what trouble you will run into next.
If you are like me and found out the hard way, join me in this article to master the beast of forms. Learn how exactly to ask for the right data or submit whatever is entered.
Table of Contents
- Forms are just tiny wrappers around HTTP
- GET and POST conventions
- Dynamic Submission - When you don't want to reload
- Submitting another format
- Make good use of form properties - configure AJAX via HTML
Forms are just tiny wrappers around HTTP
If HTML and CSS is all you use to create your forms, you will soon discover the border of what is possible and impossible.
Why are forms so exhausting? It is not the HTML that is exceptionally hard or tough to write and figure out. It is the deceptive way how form attributes make you think, you can build forms with just raw HTML and some CSS sprinkled in.
If you are knowledgable enough, you know what else is required:
- A server-side piece of code that processes the request via HTTP.
- Make the experience seamless and without reloading the page once - using JavaScript.
Piecing all that together is tiresome.
But you are not alone!
After reading this article, you will be able to answer these questions:
- What
enctype
do you use, when the server only speaksapplication/json
? - What
method
do you use, when the<form>
element only knows aboutGET
andPOST
but you actually need toDELETE
a post? - What
action
do you use, when you want to submit data without wanting to reload the page? - How do I send two requests with one form?
A Game of Faking
There are two major rules when it comes to the properties enctype
and method
.
First:enctype only knows three types:
application/x-www-form-urlencoded
multipart/form-data
text/plain
Second:method
only knows about GET
and POST
.
The enctype
corresponds to the HTTP request header content-type
.
GET and POST conventions
When you use GET
in a form, it is sent via query parameters (?username=test
) and using text/html
.
If you set the action
to POST
, the request is automatically sent as application/x-www-form-urlencoded
and the data is put into the body
of the request. But that doesn't mean query parameters do not exist in a POST
request. In fact, you can have both query parameters and a body in a request. Usually you have only one of the two.
PHP makes this super confusing by populating both $_GET
and $_POST
in that case.
Additionally, I was pretty surprised that GET requests allow a body too. It is all just a question of convention and what fields of a request the server responds to.
Luckily, most webservers follow the same conventions. But be prepared for the wild wild web where nobody has to obey any convention and potentially run a webserver on their toaster.
GET
is generally avoided for submitting data, because the inputs are saved to your browser history and are cached.
You would want to avoid that users can easily submit a form, just by following a URL.
However, GET
is useful for asking for data, and this is where the boarders blur. You need to put data into your request, such as what data to ask for. This can be basically in any part of the URL or request. It is just convention where to put them.
Anatomy of a request:
- Query Parameters: filters, sorting, order and pagination - everything that changes the way how the requested page is displayed
- Body: complex structured or unstructured data - user data submissions
- Headers: meta data - usually only read by the browser and the server
- Method: the way how the request should be processed by the server - create, read, update, delete
- URL: single view, page or collection of data to request
The next scenarios will show you when these attributes of a <form>
actually do not play a role.
Dynamic Submission - When you don't want to reload
In principle you only use method
and action
if you want a pageload. That means reloading the same page or redirecting to another page.
As soon as you build a form that need its contents processed without page reloads, you will not get anywhere with <form>
attributes. But a form can still be used to get the accessibility bonus for free. That means the input can react on the ENTER key or a submit button. Multiple inputs are grouped together. It is less effort javascript-side to re-implement all this normal browser behavior.
An example is a search input that shows quick search results. It may look like this:
This is a form that dynamically renders the results of the query when requested to. Using javascript, we can react upon the input
event of the text input.
While the underlying mechanism to get the entries doesn't necessarily need to rely on data being requested from a server, we still use a form.
In case you are curious...
In the screenshot above, I use Vuepress. Here the list of all pages is already there as a JSON array of page objects. This way, no server request is needed to display results.
Why?
Additionally, we can we hook into the submit
event of the form and preventDefault()
. Then display results in a relative positioned container.
To push it a step further, you could have the page actually handle a pageload, if javascript is disabled, and then show the requested list. This is a perfect example of progressive enhancement.
Submitting another format
Say your API speaks JSON, do you set the enctype
to application/json
? Sorry, that does not work out of the box.
If you want to submit your data in any other format, you can forget about setting enctype
alltogether.
Once you use JSON or any other format, setting up an AJAX call becomes mandatory. That is because the encode type defines how the formdata is serialized. Natively, the browser only knows about the previously mentioned three types: plaintext, formdata and urlencoded.
There were plans to implement JSON as enctype for forms, but this was unfortunately abandoned.
Fortunately, you can convert a form to JSON very easily using FormData:
const formElement = document.querySelector('.form')
Object.fromEntries(new FormData(formElement).entries())
This works for simple transformation. Since forms are string-based, you will get almost semantically valid data.
So if you select a radio input. You don't get false
or true
but "on"
and "off"
.
Below you can see how that looks in action. I added a bit more magic to convert "on"
to true
and "off"
to false
.
{
"email": "mydog@emyhome.work",
"specie": "Dog",
"amount": 20,
"food": false
}
Below you can compare the other regular enctypes that you can send with forms by using the enctype
property.
text/plain
tShirtSize=L
tShirt=on
application/x-www-form-urlencoded
tShirtSize=L&tShirt=on
multipart/form-data
------WebKitFormBoundary3cBoF3eHzPSATbPz
Content-Disposition: form-data; name="tShirtSize"
L
------WebKitFormBoundary3cBoF3eHzPSATbPz
Content-Disposition: form-data; name="tShirt"
on
------WebKitFormBoundary3cBoF3eHzPSATbPz--
multipart/form-data
is so exhaustive, because you can also send binary data with it.
Of course - you need also a server that can do something with the data, store it to a database or consume it in some other way.
Make good use of form properties - configure AJAX via HTML
We could use the action
attribute to author the URL where data goes to. We already store in the HTML what data we want to submit with form fields, so why not where it goes to?
Even if it is only processed via javascript. This way the target URL can be configured in the form itself.
<form action="/api/users">...</form>
const form = document.querySelector('.form')
form.addEventListener('submit', event => {
let credentials = {
user: 'cueball',
password: 'correcthorsebatterystaple'
}
fetch(event.target.action, {
body: JSON.stringify(credentials),
type: 'POST',
})
})
Conclusion
Forms and their associated submission logic are tightly connected to the capabilities of the server. As soon as you need something extra, you are mostly set out to solve it all client-side or chnage your server. Depending on what is in your reach, there is always a "quick and working but incorrect" solution and a "working and correct" solution.
How do you charter unknown server territory?
Don't get stuck connecting forms and servers.
Get free on-spot advice delivered to your inbox.