A <button> element without an explicit type attribute defaults to type="submit" per the HTML Living
Standard. When such a button is inside a <form>, clicking it can submit the form, even if that was not the developer’s intent. This
is especially error-prone for buttons meant to trigger something other than submission, such as clearing a field or closing a dialog: without an
explicit type, they can unexpectedly submit the enclosing form, potentially triggering an unwanted request or navigation.
A <button> can also be associated with a <form> it is not nested in, by referencing the form’s
id through a form attribute; such a button is just as likely to trigger an unintended submission.
The HTML specification defines three valid type values for buttons: submit, reset, and button. A
<button> with an invalid type value, e.g. type="action", is always flagged, regardless of whether the
button is inside a <form>: the value is not a mistake that only matters in some contexts, and if the button is ever moved into a
<form> or reused there, it silently falls back to the same unintended submit behavior described above.
Setting an explicit type on buttons inside a <form> or associated with one through a form attribute,
and always using a valid value, removes this ambiguity and makes each button’s purpose explicit regardless of the browser rendering it.
This rule does not raise an issue for a missing type only when the <button> is neither inside a
<form> nor associated with one through a form attribute, since there is then no submission to trigger. In React:
function Toolbar() {
return <button>Menu</button>; // Compliant: not inside a <form> and has no "form" attribute
}
In a Vue template:
<template> <button>Menu</button> <!-- Compliant: not inside a <form> and has no "form" attribute --> </template>
function SearchForm() {
return (
<form action="/search">
<input type="text" name="q" />
<button>Search</button> // Noncompliant: defaults to type="submit"
<button onClick={handleClear}>Clear</button> // Noncompliant: defaults to type="submit"
</form>
);
}
function SearchForm() {
return (
<form action="/search">
<input type="text" name="q" />
<button type="submit">Search</button>
<button type="button" onClick={handleClear}>Clear</button>
</form>
);
}
<template> <button type="action">Save</button> <!-- Noncompliant: "action" is not a valid type --> </template>
<template> <button type="submit">Save</button> </template>
<template> <form id="search" action="/search"></form> <button form="search">Clear</button> <!-- Noncompliant: defaults to type="submit" and submits the "search" form --> </template>
<template> <form id="search" action="/search"></form> <button form="search" type="button">Clear</button> </template>
<button> element -
type attributebutton element -
type