HTML Guides for form attribute
Learn how to identify and fix common HTML validation errors flagged by the W3C Validator — so your pages are standards-compliant and render correctly across every browser. Also check our Accessibility Guides.
A <form> can't contain another <form>, so when the parser finds a second <form> start tag while one is still open, it drops that tag along with its action, method and id.
The fields inside the ignored form then belong to the outer one. In the invalid example below, the "Delete account" button submits the account form to /account, and nothing is ever sent to /account/delete. The inner </form> also closes the outer form early, so any fields after it end up outside any form, and the validator reports the last </form> as Stray end tag “form”.
A common cause is a page template that wraps the whole page in one form, with a search box or newsletter signup inside it that adds a form of its own. A missing </form> causes it too. If the parent element of the first form closes before the form does, the parser still treats that form as active, and it ignores the next <form> on the page.
Move the inner form out so the two forms are siblings. When a button or field has to stay inside one form's layout but submit a different form, give that form an id and point the control at it with the form attribute: <button type="submit" form="delete-account">. The <button>, <input>, <select> and <textarea> elements all accept form. The form it points to can sit anywhere in the document, and it can be empty, as in the valid example below.
Invalid example
<form action="/account" method="post">
<label for="email">Email</label>
<input type="email" id="email" name="email">
<button type="submit">Save</button>
<form action="/account/delete" method="post">
<button type="submit">Delete account</button>
</form>
</form>
Valid example
<form action="/account" method="post">
<label for="email">Email</label>
<input type="email" id="email" name="email">
<button type="submit">Save</button>
<button type="submit" form="delete-account">Delete account</button>
</form>
<form id="delete-account" action="/account/delete" method="post"></form>
A <form> can't sit directly inside a <table>, <thead>, <tbody>, <tfoot> or <tr>: wrap the whole table in the form, or put the form inside a single <td> or <th> cell.
Table elements only accept specific children. A <table> holds <caption>, <colgroup>, <thead>, <tbody>, <tfoot> and <tr>, and a <tr> holds <td> and <th>. A <form> wrapped around one or more rows breaks that structure.
The browser's parser handles this case in a special way. It creates the form as an empty element at the spot where the tag appears, closes it right away, and drops the matching </form> end tag, which the validator reports as a separate Stray end tag “form” error. Browsers still link the fields in the following rows to that empty form, so submitting often appears to work. But the fields are not inside the form in the DOM: a selector like form input won't find them, and if a script moves or re-renders those rows, the fields lose their form.
When each row needs its own form, such as an "Update" button per cart item, keep the <form> elements outside the table and link each field and button to its form with the form attribute, which takes the form's id.
Invalid example
<table>
<form action="/cart" method="post">
<tr>
<td><label for="qty">Quantity</label></td>
<td><input type="number" id="qty" name="qty"></td>
<td><button type="submit">Update</button></td>
</tr>
</form>
</table>
Valid example
<form action="/cart" method="post">
<table>
<tr>
<td><label for="qty">Quantity</label></td>
<td><input type="number" id="qty" name="qty"></td>
<td><button type="submit">Update</button></td>
</tr>
</table>
</form>
Valid example with one form per row
<form id="item-1" action="/cart/1" method="post"></form>
<form id="item-2" action="/cart/2" method="post"></form>
<table>
<tr>
<td><input type="number" name="qty" form="item-1" aria-label="Quantity for item 1"></td>
<td><button type="submit" form="item-1">Update</button></td>
</tr>
<tr>
<td><input type="number" name="qty" form="item-2" aria-label="Quantity for item 2"></td>
<td><button type="submit" form="item-2">Update</button></td>
</tr>
</table>
Validate at scale.
Ship accessible websites, faster.
Automated HTML & accessibility validation for large sites. Check thousands of pages against WCAG guidelines and W3C standards in minutes, not days.
1K Weekly
1,000 monthly checks. Cancel anytime.
Get 1K Weekly →Join teams across 40+ countries