The HTMLFormElement is weird. Although it was designed to make working with forms easier in the early days of the web, there are many subtle problems and inconsistencies that create nasty JavaScript bugs.

Let’s say you have a simple contact form on your website, like this:

<form action="/contact" method="POST" id="myForm">
  <input type="text" name="name" placeholder="Name" />
  <input type="email" name="email" placeholder="Email" />
  <input type="submit" name="submit" value="Submit" />

All is well until we try to attach some JavaScript to this form. If we need to inject some asynchronous action before the submit fires, like an AJAX lookup or send an analytics event, the code might look something like:

var form = document.querySelector("#myForm");
form.addEventListener("submit", function (evt) {

  myAsyncAction(function callback() {

  return false;

But when we run this, it generates an error:

TypeError: form.submit is not a function

Wait, what? How is form.submit not a function? MDN says its a function, WHAT IS EVEN GOING ON? Then we see, hidden in the text is this really important and interesting line:

If a form control has a name or id of submit it will mask the form's submit method.

Any named form control can be accessed as a property on the form object. In the example above would reference the Name input and would reference the Email input. Unfortunately, we gave our submit button a name too, so rather than being the submit() function we want, it gives us a reference to the submit input.

HTMLFormElement is just trying to be helpful, but this is really weird. What happens if we do other important properties, like class or id?

<form class="form-control" id="myForm">
  <input name="id" />
  <input name="className" />
  var form = document.querySelector("#myForm");; // => <input name="id" />
  form.className // => <input name="className" />

That feels like a bug waiting to happen. Even more weird, if we set the properties, like = "foo";, that still works, even though we cannot get the value because it has been hidden by the input control.

UPDATE Our friend Philip Tellis pointed out how that to get to the real attributes of the form, you need to use getAttribute(). To submit the form, you need to use Both of these strategies bypass the form control helper weirdness.

When you’re building form controls, take care to not hide default properties with your names. It might even be worth considering prefixing your names to avoid the many cases of bugs that could arise from this weird behavior of the HTMLFormElement. Speaking of bugs, try TrackJS today, free for 30 days, and we’ll help you know when these bugs impact your visitors.