> ## Documentation Index
> Fetch the complete documentation index at: https://docs.formbase.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# JavaScript + AJAX

> Submit to Formbase with fetch, XHR, or jQuery for full UI control.

Use JavaScript submissions when you need loading states, inline errors, or single-page app behavior. Formbase accepts `FormData` and JSON payloads, so you can post directly from the browser.

Browser requests receive a `303` redirect instead of JSON. When submitting with JavaScript, treat a `303` status as success or send the request from your server for a JSON response.

<Steps>
  <Step title="Build your form">
    Create a normal HTML form with `name` attributes. JavaScript will serialize it.
  </Step>

  <Step title="Submit with your preferred method">
    <Tabs>
      <Tab title="Fetch">
        ```html theme={null}
        <form id="contact-form">
          <input name="name" placeholder="Name" required />
          <input name="email" type="email" placeholder="Email" required />
          <textarea name="message" required></textarea>
          <button id="submit" type="submit">Send</button>
        </form>
        <p id="status" role="status"></p>

        <script>
          const form = document.getElementById('contact-form');
          const status = document.getElementById('status');

          form.addEventListener('submit', async (event) => {
            event.preventDefault();
            status.textContent = '';

            const response = await fetch('https://formbase.dev/s/YOUR_FORM_ID', {
              method: 'POST',
              body: new FormData(form),
              redirect: 'manual',
            });

            if (response.status === 303 || response.ok) {
              status.textContent = 'Submitted!';
              form.reset();
              return;
            }

            status.textContent = 'Submission failed.';
          });
        </script>
        ```

        `redirect: 'manual'` prevents the browser from following the redirect and running into CORS issues.
      </Tab>

      <Tab title="XHR">
        ```html theme={null}
        <form id="xhr-form">
          <input name="name" placeholder="Name" required />
          <button type="submit">Send</button>
        </form>
        <p id="xhr-status"></p>

        <script>
          const xhrForm = document.getElementById('xhr-form');
          const xhrStatus = document.getElementById('xhr-status');

          xhrForm.addEventListener('submit', (event) => {
            event.preventDefault();
            const xhr = new XMLHttpRequest();
            xhr.open('POST', 'https://formbase.dev/s/YOUR_FORM_ID');
            xhr.onload = () => {
              xhrStatus.textContent = xhr.status === 303 || xhr.status === 200
                ? 'Submitted!'
                : 'Submission failed.';
            };
            xhr.send(new FormData(xhrForm));
          });
        </script>
        ```

        XHR gives you full control over success and error states.
      </Tab>

      <Tab title="jQuery">
        ```html theme={null}
        <form id="jquery-form">
          <input name="name" placeholder="Name" required />
          <button type="submit">Send</button>
        </form>
        <p id="jquery-status"></p>

        <script>
          $('#jquery-form').on('submit', function (event) {
            event.preventDefault();

            $.ajax({
              url: 'https://formbase.dev/s/YOUR_FORM_ID',
              method: 'POST',
              data: new FormData(this),
              processData: false,
              contentType: false,
              complete: function (xhr) {
                $('#jquery-status').text(
                  xhr.status === 303 || xhr.status === 200
                    ? 'Submitted!'
                    : 'Submission failed.'
                );
              }
            });
          });
        </script>
        ```

        jQuery works as long as you send `FormData` and disable automatic processing.
      </Tab>
    </Tabs>
  </Step>
</Steps>

<Callout type="tip">
  If you need a JSON response, submit from your server (for example, an API route or server action) instead of the browser.
</Callout>
