Charles Harries

| Stream

Form input inconsistencies

The <input> element and the <select> element submit different values to the backend, depending on how you use 'em.

Here's a question for you: imagine that you've got an HTML form something like this:

<form action="/" method="POST">
	<label for="name">Your name</label>
	<input name="name" type="text" />
 
	<!-- This select purposely left blank -->
	<label for="favourite_food">Your favourite food</label>
	<select name="favourite_food"></select>

	<button type="submit">Save preferences</button>
</form>

Now imagine that a user clicks the Save preferences button and submits the form. What does the network payload look like? I thought that it would look something like name=&favourite_food=—that is to say, that the name and favourite_food variables would be submitted as empty strings—but that's not the case.

It submits instead firstname=, and that's it. The empty <select> is ignored. Same goes for if you pull the ol' select placeholder trick:

<!-- Won't be submitted either -->
<select name="favourite_food">
	<option selected disabled hidden>Choose a food...</option>
</select>

Can't seem to find anything about it on MDN—hopefully this helps someone else struggling to find their data on the backend!

Update: As Šime Vidas points out on Twitter, this is because "only non-disabled, selected <option> element values are added to the form’s 'entry list'", according to the HTML spec. Which means that the following won't be submitted either either:

<select name="favourite_food" value="Cake"></select>

So the actual value of the select comes from the <option>, not the <select> itself. I love to find out that HTML elements fit together like that. And it also means, given the above select:

const select = document.querySelector('[name="favourite_food"]');
console.log(select.value) // => ""

Web Code