loading...
Cover image for If there is an input, there should be a form

If there is an input, there should be a form

tomekdev_ profile image 🤓 Tomek Nieżurawski Originally published at tomekdev.com on ・2 min read

This post was originally published on https://tomekdev.com/posts/input-and-form. Go there to read a bit more interactive and style richer version ✌️


I often see in Single Page apps a situation where someone uses just an <input> field. Sometimes in the accompaniment of <label> if you happen to work with a pro 🌟. It feels that when we gained control of inputs with two-way binding and we started handling onclick events on buttons with our fancy frameworks, we forgot the old way of doing things.

The old way, and the right way

The headline of this section may suggest that the old way and the right way are two different things. Where in fact, it's the opposite. If you come back with your memory before the frameworks (or ajax) era you see that people were using a <form> element when dealing with inputs and buttons.

In the past we were extensively using <form method=""> to process the input. I encourage you to still use a form element. It comes with benefits.

Common mistake

I use the keyboard to navigate and interact with pages. That speeds up everything. So for me one of the biggest pitfalls of using <input> without a <form> is that the input is not auto-submittable, so to say.

When you hit ENTER in the field that is inside the form then the form is submitted. That's very convenient for solo-input interfaces like a modal below:

Alt Text

You don't have to touch your mouse or touchpad and click Save button 🎉. That would be a waste of time!

Solution

It's a common mistake to bind your action to a <button> where in fact all you have to do is wrap your<input> with a <form> and assign submit event to a form:

<form id="my-form">
  <input name="example" type="text" />
  <button type="submit">Submit</button>
</form>
Enter fullscreen mode Exit fullscreen mode
const form = document.getElementById('my-form');

form.addEventListener('submit', function handleSubmit(event) {
  alert('Submit clicked');
  event.preventDefault();
});
Enter fullscreen mode Exit fullscreen mode

Don't forget to prevent default behavior from firing and run your custom behavior. It could be running validation and actually sending the data.

One more thing that you should consider is always specifying button's type. It's submit by default in most browsers but Internet Explorer is different in this case and has button as a default type.

Discussion

pic
Editor guide
Collapse
patarapolw profile image
Pacharapol Withayasakpunt

A common pattern I use in Vue

<form @submit.prevent="doSearch">
  <input
    name="q"
    type="search"
    v-model="q"
    @keydown.enter="doSearch" />
  <button type="submit">Submit</button>
</form>
Enter fullscreen mode Exit fullscreen mode

It works not only on Desktop, but also on Mobile.

I also realized that not only <form> is important, but also <button type="submit">.

Collapse
tomekdev_ profile image
🤓 Tomek Nieżurawski Author

I'm not very familiar with Vue but I think you can omit:

@keydown.enter="doSearch"
Enter fullscreen mode Exit fullscreen mode

The beauty of <form></form> + <button type="submit">Submit</button> is that you don't have to manually handle ENTER key on an input. Which is very convenient if you have multiple inputs :)

Collapse
whitewcallum580 profile image
Callum White

Just out of interest, how would you extract the values from the form when onsubmit is called?

Collapse
tomekdev_ profile image
🤓 Tomek Nieżurawski Author

It depends, if I use a framework (say React) I'd just use the state to retrieve the data and don't bother about anything.

In Vanilla solution I'd go for FormData:

const form = document.getElementById('my-form');

form.addEventListener('submit', function handleSubmit(event) {
  event.preventDefault();

  const formData = new FormData(event.target);
  const object = {};
  formData.forEach((value, key) => {object[key] = value});

  console.log(object);
});
Enter fullscreen mode Exit fullscreen mode

FormData object is not easy to use so in the example above I already "re-write" it to object structure where I can potentially convert it into JSON (through JSON.stringify(object)). Unfortunately, that's not the end of the story if you have to deal with multi-select values but with a little tweak in the forEach callback it can be managed.

So -> FormData unless you already keep the state somewhere 🤷‍♂️