title: How to ensure a JavaScript .submit() respects event handlers attached to the form
body: <p><strong>NOTE</strong>
  <em>So I actually managed to solve this issue whilst writing out the problem, but thought I would post anyway in case it helps anyone else out (a brief search on Stack Overflow indicated that no one else seemed to have asked quite the same question)</em></p>
  
  <hr>
  
  <p>So I have a form with a web component that is handled via JavaScript, like so:</p>
  
  <pre><code>&lt;form id="myform"&gt;
    &lt;input type="text" value="example" tabindex="1" /&gt;
    &lt;web-component tabindex="2"&gt;&lt;/web-component&gt;
    &lt;input type="submit" tabindex="3" /&gt;
  &lt;/form&gt;
  
  &lt;script&gt;
  let form = document.getElementById('myform');
  
  form.addEventListener('submit' (e) =&gt; {
    e.preventDefault();
  
    console.log('Form is posting');
  
    // Handle form stuff here
  })
  &lt;/script&gt;
  </code></pre>
  
  <p>With my web component, I want to be able to 'submit' the form when tabbed to the web component and pressing 'enter', such that I have the following handler within the web component:</p>
  
  <pre><code>class WebComponent extends HTMLElement {
    constructor() {
      ...
  
      let form = this.closest('form');
  
      this.addEventListener('keydown', (e) =&gt; {
        if(form &amp;&amp; e.code === 'Enter') form.submit();
      })
    }
  }
  </code></pre>
  
  <p>The problem I have got is that <code>form.submit()</code> submits the form, but doesn't fire an event that gets monitored, causing the <code>form</code> event handler to not run and the form to simply post without any JS validation. My first thoughts for getting the form to work is to change the form submit function to a named function, something like:</p>
  
  <pre><code>form.addEventListener('submit', handleFormSubmission);
  
  myComponent.addEventListener('keydown', (e) =&gt; {
    if(e.code === 'Enter') handleFormSubmission();
  })
  </code></pre>
  
  <p>But the problem here is that the web component cannot then necessarily be used for multiple forms, or would then need to have an event handler added to it each time it is called to ensure that it corresponds with the function name associated with the form. This would have to be done outside the component, and really reduce the readability.</p>
  
  <p>The other option I have considered is to search the form for an <code>input[type=submit]</code> or <code>button[type=submit]</code> and trigger a click on that, but that seems somewhat clunky to me.</p>
  
  <p>After some searching, I came across <code>dispatchEvent</code>, which fires a <code>submit</code> event as opposed to simply firing <code>submit()</code>, like so:</p>
  
  <pre><code>class WebComponent extends HTMLElement {
    constructor() {
      ...
  
      let form = this.closest('form');
  
      this.addEventListener('keydown', (e) =&gt; {
        if(form &amp;&amp; e.code === 'Enter') form.dispatchEvent(new Event('submit'));
      })
    }
  }
  </code></pre>
  
  <p>And by now I am <strong>very</strong> close - the <code>submit</code> handler, and the <code>console.log</code> fires, but the <code>e.preventDefault()</code> is not respected, meaning that if my JS validation wants to terminate the submission for any reason, it can't... By default.</p>
  
  <p>A bit more searching (i.e. actually bothering to read the spec, rather than just plough ahead full-throttle and throwing mud at the wall to see what sticks) I realised that the <code>Event</code> constructor takes an optional object for settings, such that you can have (e.g.) <code>new Event('submit', {bubbles: true, cancelable: true})</code>. Finally, it works:</p>
  
  <pre><code>let form = document.getElementById('myform');
  
  form.addEventListener('submit' (e) =&gt; {
    e.preventDefault();
  
    console.log('Form is posting');
  
    // Handle form stuff here
  });
  
  class WebComponent extends HTMLElement {
    constructor() {
      ...
  
      let form = this.closest('form');
  
      this.addEventListener('keydown', (e) =&gt; {
        if(form &amp;&amp; e.code === 'Enter') form.dispatchEvent(new Event('submit', {cancelable: true}));
      })
    }
  }
  </code></pre>