DEV Community

Nehal Gulati for EHUB IT Web Solution

Posted on Fully Autonomous

A Mobile Enquiry Form Is a Small State Machine

A form can look finished while its most important behaviour is still undefined. What happens when the network fails? What does a second tap do? Does the success message mean the server accepted the enquiry, or only that JavaScript ran?

Treating the form as a small state machine makes those questions easier to answer. This walkthrough covers a contact form, but the same approach works for demo requests and project enquiries.

Start with four states

Use idle, submitting, success, and error. Browser validation happens before the submit handler runs. The handler then moves into submitting; only the server response determines whether it can move into success.

State Submit button Message User input
Idle Available Brief instructions Editable
Submitting Disabled Sending Preserved
Success Available Request accepted Clear only after acceptance
Error Available Actionable retry message Preserved

A disabled button reduces accidental double taps. It does not provide server-side duplicate protection: that requires an idempotency mechanism or another deliberate backend rule.

Keep the HTML useful before JavaScript

Give every field a visible label. Use autocomplete tokens to make mobile input less tedious. A telephone field helps the keyboard, but it does not establish that a number is valid or reachable.

<form action="/enquiries" method="post" id="enquiry-form">
  <label for="contact-name">Your name</label>
  <input id="contact-name" name="name"
         autocomplete="name" required maxlength="100">

  <label for="contact-phone">Phone number</label>
  <input id="contact-phone" name="phone" type="tel"
         autocomplete="tel" required maxlength="30">

  <label for="project">What would you like to build?</label>
  <textarea id="project" name="project"
            rows="3" required maxlength="2000"></textarea>

  <button type="submit">Send enquiry</button>
  <p role="status" aria-live="polite" id="form-status"></p>
</form>
Enter fullscreen mode Exit fullscreen mode

The action is illustrative: a real application needs a matching server route. That route should support ordinary form submission as well as the enhanced JSON response. Add the application's CSRF protection, server validation, abuse controls, and appropriate privacy information before deployment.

Define what acceptance means

For an enhanced request, establish a response contract such as:

{ "accepted": true }
Enter fullscreen mode Exit fullscreen mode

The server should return this only after it has durably recorded or queued the enquiry according to the application's design. An accepted enquiry is not proof that an email reached an inbox, a salesperson responded, or a sale occurred.

const form = document.querySelector('#enquiry-form');
const button = form.querySelector('button[type="submit"]');
const status = document.querySelector('#form-status');
let submitting = false;

form.addEventListener('submit', async (event) => {
  event.preventDefault();
  if (submitting) return;

  submitting = true;
  button.disabled = true;
  status.textContent = 'Sending your enquiry…';

  try {
    const response = await fetch(form.action, {
      method: 'POST',
      headers: { Accept: 'application/json' },
      body: new FormData(form)
    });
    const result = await response.json();

    if (!response.ok || result.accepted !== true) {
      throw new Error('Enquiry was not accepted');
    }

    status.textContent = 'Your enquiry has been received.';
    form.reset();
  } catch {
    status.textContent =
      'We could not confirm receipt. Please check your connection or contact us.';
  } finally {
    submitting = false;
    button.disabled = false;
  }
});
Enter fullscreen mode Exit fullscreen mode

fetch() does not reject just because the server returns an HTTP error. The explicit response.ok check matters. Malformed or unexpected JSON also goes through the error path here.

A lost response creates an awkward case: the server might have accepted the request even though the browser cannot confirm it. Preserve the input and use honest wording. For stronger retry guarantees, implement a server-recognised idempotency key rather than assuming a second request is safe.

Test the unsuccessful paths too

Before launch, check an empty submission, invalid input, a slow response, a server error, and a rapid double tap. Verify keyboard navigation, visible focus, readable labels, and a success message announced without moving focus unexpectedly. Use synthetic contact details in a test environment.

If analytics is added, place the enquiry event after confirmed acceptance and honour the site's measurement preferences. Do not put contact details or the free-text message into an analytics payload. A button click should remain a separate interaction event.

For the business-side decisions behind the fields, the EHUB mobile enquiry-form planning guide covers what to agree before implementation.

Technical references: HTML forms and Fetch response handling.


Published by EHUB. Prepared with AI assistance.

Top comments (0)