Button type matters, after all
The <button type='button'>
construct is HTML's eat your veggies. It's good advice and you should always do it. Between you and me, we both know it's a bit silly: of course a button is a button, I mean…
Well, buddy, if you've been omitting your type
attribute with impunity, I'm here to tell you that one day, without warning, this habit is going to bite you in the ass. I know it because *cue pensive piano music* it happened to me. One day I did a boo-boo and it only occurred to me a while later that the boo-boo was there.
In all honesty, the actual event lacked the gravitas of my dramatization here, but I thought it was delightfully unintuitive form behavior so I did a twete. Seeing other people go huh, I thought I'd unpack the idea a bit.
Here is the markup of a typical JavaScript-enhanced log in form. Excuse the inline event listeners, which are used to make the code sample simpler:
<form action='' onsubmit='login(…); return false;'>
<p>
<label>Username: <input type='text' name='username'/></label>
</p>
<p>
<label>Password: <input type='password' name='password'/></label>
</p>
<button type='submit'>Log in</button>
</form>
Now let's say you add to the form a button that reveals the password in plain text:
<form action='' onsubmit='login(…); return false;'>
<p>
<label>Username: <input type='text' name='username'/></label>
</p>
<p>
<label>Password: <input type='password' name='password'/></label>
<button onclick='this.form.password.type="text"; return false;'>
Show password
</button>
</p>
<button type='submit'>Log in</button>
</form>
What unexpected behavior have you introduced to this form with the addition of that button?
Answer: If the user presses the Enter key after they've typed in their password, instead of submitting the form, the user's password is revealed in plain text.
The Show password button lacks an explicit type='button'
and so it gets the default type='submit'
. Outside of forms, this has no ill effect: without a form to submit, the button behaves like type='button'
in that it does nothing. Put it into a form and it suddenly behaves as an actual submit button.
When the user presses the Enter key while focused on one of the form's inputs, the form gets submitted via the so-called implicit submission. The browser doesn't simply submit the form, it actually clicks the first submit button it finds in the form. From the HTML spec (emphasis mine):
If the user agent supports letting the user submit a form implicitly (for example, on some platforms hitting the "enter" key while a text control is focused implicitly submits the form), then doing so for a form, whose default button [ie. the first submit button in tree order whose form owner is that form element] has activation behavior and is not disabled, must cause the user agent to fire a
click
event at that default button.
Because the Show password button is implicitly a submit button, and it happened to be added sooner in tree order than the legit submit button, the implicit submission reveals the user's password. Ta-daa!
And that's why you always write <button type='button'>
.
Coda: actually marking up a login form
Besides the point I was trying to make about implicit form submission, there are more things that this toy markup misses, among which:
- The
autocomplete
attribute can help password managers make better choices about storing and filling in information for the form. - Users of assistive technology are not well served by the Show password functionality. If you're serious about implementing this feature, Nicolas Steenhout touches on the topic in his Show/Hide password accessibility and password hints tutorial, and the GDS document even more gotchas in Simple things are complicated: making a show password option (h/t Phil). But, more importantly, everyone seems to agree that we would be better off if browsers themselves had the feature baked in.