Skip to main content
โšก Calmops

HTML Nesting Rules: Forms in Tables and Other Common Mistakes

Introduction

HTML has strict rules about which elements can be nested โ€” leading to broken layouts, JavaScript errors, and accessibility issues. This guide covers the most common nesting mistakes and how to fix them.

The Form-in-Table Problem

The Rule

A <form> element cannot span multiple table rows. It must be completely contained within a single <td> element.

Why It Breaks

HTML parserng form submissions to fail.

Wrong: Form Spanning Table Rows

<!-- WRONG: form is inside <tr> but outside <td> -->
<table>
  <tbody>
    <tr>
      <td>Product Name</td>
      <td>ยฅ32.00</td>

      <!-- form starts here, inside <tr> but not inside <td> -->
      <form action="/carts/169" method="post">
        <td>
          <input type="number" name="cart[amount]" value="7">
          <input type="submit" value="Update">
        </td>
      </form>

      <td><a href="/carts/169" data-method="delete">Delete</a></td>
    </tr>
  </tbody>
</table>

What happens: The browser moves the <form> outside the <table>, breaking the layout. Firefox shows the invalid HTML highlighted in red in the source view.

Correct: Form Completely Inside a <td>

<!-- CORRECT: form is completely inside a <td> -->
<table>
  <tbody>
    <tr>
      <td>Product Name</td>
      <td>ยฅ32.00</td>
      <td>
        <!-- form is entirely within this <td> -->
        <fo
          <input type="number" name="cart[amount]" value="7" min="1" max="100">
          <button type="submit" class="btn btn-primary btn-sm">Update</button>
        </form>
      </td>
      <td>
        <a href="/carts/169" data-method="delete" class="btn btn-danger btn-sm">Delete</a>
      </td>
    </tr>
  </tbody>
</table>

Alternative: Use div Layout Instead of Table

For shopping carts and product lists, a flexbox or grid layout is often cleaner than a table:


  <div class="product-row">
    <span class="product-name">Product Name</span>
    <span class="product-price">ยฅ32.00</span>
ources

- [MDN: HTML Content Categories](https://developer.mozilla.org/en-US/docs/Web/HTML/Content_categories)
- [W3C HTML Validator](https://validator.w3.org/)
- [HTML Spec: The form element](https://html.spec.whatwg.org/multipage/form-elements.html#the-form-element)
- [Forms in Tables (Jukka Korpela)](https://www.cs.tut.fi/~jkorpela/forms/tables.html)
nsole shows warnings for some nesting errors.

### W3C Validator

```bash
# Online validator
# https://validator.w3.org/

# CLI validator
npm install -g html-validate
html-validate index.html

In-Browser Check

// Check for HTML parsing errors in the browser
const parser = new DOMParser();
const doc = parser.parseFromString(htmlString, 'text/html');
const errors = doc.querySelectorAll('parsererror');
if (errors.length > 0) {
  console.error('HTML parsing errors:', errors);
}

Rests, text | Other <a> elements, <button> |

| <button> | Inline elements, text | <a>, <input>, <button> | | <ul>, <ol> | <li> elements | Direct text, other elements | | <table> | <thead>, <tbody>, <tfoot>, <caption> | Direct <tr> or <td> | | <tr> | <td>, <th> | Direct text, other elements | | <form> | Block and inline elements | Another <form> |

Validating Your HTML

Browser DevTools

Firefox highlights invalid HTML in red in the source view. Chrome’s DevTools co

–>

Cell
Cell
```

HTML Content Model Reference

Understanding content models helps avoid nesting mistakes:

Element Can Contain Cannot Contain
<p> Inline elements, text Block elements (<div>, <p>, <ul>)
<span> Inline elements, text Block elements
<a> Inline elemen button inside a link –>

Click me


### List Items Outside Lists

```html
<!-- WRONG: <li> must be inside <ul> or <ol> -->
<div>
  <li>Item 1</li>
  <li>Item 2</li>
</div>

<!-- CORRECT -->
<ul>
  <li>Item 1</li>
  <li>Item 2</li>
</ul>

Table Structure Violations

<!-- WRONG: <td> directly inside lid</div>
</span>

<!-- CORRECT: use block inside block, or inline inside inline -->
<div>
  <div>This is valid</div>
</div>

<span>
  <em>This is valid</em>
</span>

Paragraphs Inside Paragraphs

<!-- WRONG: <p> cannot contain block elements -->
<p>
  Some text
  <div>A div inside a paragraph</div>
  More text
</p>

<!-- CORRECT: use separate paragraphs or a div -->
<p>Some text</p>
<div>A div</div>
<p>More text</p>

Interactive Elements Inside Interactive Elements

<!-- WRONG: (button clicks have no effect), the cause is often invalid HTML nesting. Turbolinks is stricter about HTML validity than a regular page load.

**Symptoms:**
- Button click does nothing
- No network request in DevTools
- Works after disabling Turbolinks

**Fix:** Ensure the form is completely inside a `<td>`, not spanning `<tr>` boundaries.

## Other Common HTML Nesting Mistakes

### Block Elements Inside Inline Elements

```html
<!-- WRONG: <div> (block) inside <span> (inline) -->
<span>
  <div>This is inva    <form action="/carts/169" method="post" class="quantity-form">
      <input type="number" name="cart[amount]" value="7" min="1" max="100">
      <button type="submit">Update</button>
    </form>
    <a href="/carts/169" data-method="delete">Delete</a>
  </div>
</div>

If you’re using Rails with Turbolinks and a form inside a table isn’t working

Comments