# Can you nest HTML forms?

[According to this SO post](https://stackoverflow.com/questions/379610/can-you-nest-html-forms), well... no. What if there was a way to do it anyway ?

## Nesting form is not allowed

If you try to do this:

```xml
<form action="/main">
    <input type="text" name="main_field">
    <form action="/sub">
        <input type="text" name="sub_field">
        <input type="submit">
    </form>
    <input type="submit">
</form>
```

You will notice that the nested form is discarded when parsed by the browser because [it's not allowed in the spec](https://www.w3.org/TR/html5/forms.html#the-form-element). Nested forms might seem dumb, but it can be useful sometimes, for example when nesting some kind of modal in a form with specific actions.

It turns out this was exactly my use case with [pop-modal](https://github.com/lekoala/pop-modal) and I found a nice solution that I wanted to share with you.

## A fake form to the rescue

Let's tweak our snippet a little bit

```xml
<div id="holder">
<form action="/main">
    <input type="text" name="main_field">
    <nested-form action="/sub">
        <input type="text" name="sub_field">
        <input type="submit">
    </nested-form>
    <input type="submit">
</form>
</div>
```

Here, I converted the `form` tag to a custom `nested-form` tag. This way, I can keep the form tag and declare any attribute I want. But obviously, this is not going to work, so we need to do a few things.

```javascript
const holder = document.querySelector("#holder");
const nestedForm = holder.querySelector("nested-form");
const form = document.createElement("form");
nestedForm.getAttributeNames().forEach((attr) => {
    form.setAttribute(attr, nestedForm.getAttribute(attr));
});
form.append(...nestedForm.childNodes);
nestedForm.remove();
holder.append(form);
```

This will effectively "unnest" the forms, but it will also move the fields in the dom. In my case, since I'm working in a modal, that's good enough, but maybe you actually need these fields to stay in place.

## A fake form with fake fields

Let's say you cannot move the form in the dom. Here is a slightly more complex solution. Thanks to the `form` attribute, we target a form with nested hidden inputs. Those hidden input get the value for the original inputs through a change listener. It's not a bulletproof solution, but this works well for simple forms.

```javascript
const holder = document.querySelector("#holder2");
const nestedForm = holder.querySelector("nested-form");
const form = document.createElement("form");
document.body.append(form);
nestedForm.getAttributeNames().forEach((attr) => {
  form.setAttribute(attr, nestedForm.getAttribute(attr));
});
form.id = form.id|| "form-" + (+new Date());
nestedForm.querySelectorAll('[type="submit"]').forEach((btn) => {
  btn.setAttribute("form", form.id);
});
nestedForm.querySelectorAll("input,textarea,select").forEach((input) => {
  const hidden = document.createElement('input');
  hidden.type = "hidden";
  hidden.name = input.name;
  form.appendChild(hidden);
  // Sync values
  input.addEventListener('change', (ev) => {
    hidden.value = input.value;
  })
});
```

If you want to give this a try, here is a codepen

%[https://codepen.io/lekoalabe/pen/qBGrWKY]
