// architecture
HTML form vs JavaScript form — which should you use?
Every "JavaScript form" still renders HTML inputs — the difference is whether submission relies on the browser's native behavior or on fetch / client-side frameworks. Here is how to choose, with patterns that work on static sites and in React apps.
At a glance
| Factor | Native HTML form | JavaScript-enhanced form |
|---|---|---|
| Works without JS | Yes | No (by definition) |
| Page reload on submit | Usually yes | No — stays on page |
| Browser validation | required, type, pattern |
Custom + often duplicates HTML attrs |
| Accessibility | Excellent baseline | Requires manual ARIA care |
| Best backends | Formspree, Basin, Netlify | Same + JSON APIs, Formcarry |
| Bundle size | Zero | Framework + handler code |
Native HTML form — the baseline
A plain HTML form uses the browser's built-in submission pipeline. Set action and method, add semantic labels, and the form works even if JavaScript fails to load — critical for accessibility and flaky mobile networks.
Pure HTML (no JavaScript)
<form action="https://formspree.io/f/xyz" method="POST">
<input type="email" name="email" required />
<button type="submit">Subscribe</button>
</form>
Use native HTML when: you ship static sites, care about Core Web Vitals, want maximum accessibility, or your users may block scripts.
JavaScript form — enhanced UX
Intercept submit, call preventDefault(), send data with fetch, then show inline success or error states. Formspree, Getform, and Formcarry all accept application/json POSTs for this pattern.
Progressive enhancement with fetch
const form = document.querySelector('#contact');
form.addEventListener('submit', async (e) => {
e.preventDefault();
const res = await fetch(form.action, {
method: 'POST',
body: new FormData(form),
headers: { Accept: 'application/json' }
});
if (res.ok) form.replaceWith(successMessage);
});
Use JavaScript when: you are in a SPA (React, Vue, Svelte), need multi-step flows without full page loads, or want instant inline validation feedback.
Progressive enhancement (recommended)
Build the HTML form first so it works without scripts. Layer JavaScript to prevent reload and improve feedback. If the script errors, users can still submit — you do not lose leads.
- Write valid HTML with labels,
required, and correctautocomplete - Test submission with JavaScript disabled
- Add a submit handler that enhances, not replaces, the native flow
- Mirror server-side validation rules in client code when possible
Embed widgets: a third category
Form builders like forms.app and Jotform ship their own JavaScript. You paste embed code — neither pure HTML nor your custom JS. Trade-off: less control, faster setup, hosted validation and spam tools.
Accessibility note
JavaScript forms often break accessibility when developers forget focus management, live regions for errors, and keyboard traps in custom widgets. Native HTML gives you submit-on-Enter, label association, and screen-reader announcements for free. If you go JS-heavy, test with VoiceOver or NVDA.