WebToolsPlanet
Developerguide·7 min read

How HTML Form Action and Method Work

How the HTML form action and method attributes work — GET vs POST, when the browser navigates, and submitting without a page reload. Free generator included.

Published 7/23/2026
Updated 7/23/2026

Every HTML form has two attributes doing all the real work, and both are easy to get wrong in ways that don't show an error — they just quietly send data somewhere you didn't intend, or not at all.

Quick Answer

action sets the URL a form submits to; method sets how — GET appends the data to that URL as a query string and is meant for retrieving data (like a search box), while POST sends it in the request body and is the correct choice for anything that creates, changes, or emails data. Leaving method unset defaults to GET, which is the single most common cause of a broken form submission. Form Studio sets both correctly based on your delivery configuration.


Use the Free Tool

Form Studio's Delivery tab lets you set a custom endpoint URL and HTTP method visually, and generates the matching action/method attributes (or the equivalent fetch call, for the JavaScript-framework export formats) automatically — no risk of the mismatch described below.


What action Does

action is the URL the browser sends the form's data to when it submits:

<form action="/submit-contact" method="POST">

If you omit action entirely, the form submits to the current page's URL — which is a valid, deliberate choice for a form handled by a server-rendered page reload, but almost never what you want for a client-side or static-site form, where it just reloads the current page with no visible effect.

What method Does

method decides how the data gets to that URL — and this is where most of the meaningful behavior differences live.

GET: Data in the URL

<form action="/search" method="GET"> <input type="text" name="q"> </form>

Submitting this form navigates the browser to /search?q=whatever-was-typed. The data becomes part of the URL itself — visible in the address bar, saved in browser history, logged in server access logs, and bookmarkable/shareable as a link. This is exactly right for a search box or a filter form, where "the current state is a URL you can share" is a feature.

It is wrong for anything containing personal information, a password, or any data you don't want sitting in browser history and server logs in plain text.

POST: Data in the Request Body

<form action="/contact" method="POST"> <input type="text" name="name"> <input type="email" name="email"> </form>

The same data instead travels in the HTTP request body, invisible in the URL and not stored in browser history. This is the correct method for a contact form, a login form, a signup form, or any form-to-email endpoint — nearly everything that isn't a pure search/filter interface.

The Default Is GET

If you omit method entirely, the browser defaults to GET. This is the single most common reason a form-to-email or API-backed form silently fails: most endpoint providers and API routes expect POST and reject a GET request outright, often with a 404 or 405 error that has nothing obviously to do with a missing attribute.


What Happens on Submit, Step by Step

  1. The user clicks a type="submit" button (or presses Enter inside a text input).

  2. The browser collects every field with a name attribute inside the form — fields without one are silently excluded.

  3. It builds the request: appended to the URL for GET, placed in the body for POST.

  4. It navigates to action (for GET) or sends the request to it (for POST), and by default, replaces the current page with whatever that URL returns — a full page reload.

  5. The <form> element disappears from the DOM the instant navigation starts, unless something has prevented that default behavior.

That last point is why AJAX and framework-based forms all start with the same line: event.preventDefault().


Submitting Without a Page Reload

For a single-page app, a React/Vue/Svelte component, or any form where you want to show a success message without leaving the page, you intercept the submit event and send the request with JavaScript instead of letting the browser navigate:

<form id="contact-form" method="POST"> <input type="text" name="name"> <button type="submit">Send</button> </form> <script> document.getElementById('contact-form').addEventListener('submit', async function (event) { event.preventDefault(); const formData = new FormData(event.target); const response = await fetch('/contact', { method: 'POST', body: formData, }); // handle response.ok, show a success message, etc. }); </script>

action becomes optional here — the JavaScript decides where the request goes, via the URL passed to fetch, independent of anything set on the <form> tag itself. Keeping method="POST" on the tag is still good practice as a fallback for the rare case JavaScript fails to load.


Step-by-Step Workflow

Step 1: Decide if the form retrieves data (use GET) or submits/changes data (use POST) — nearly every contact, signup, and lead-gen form is POST.

Step 2: Set action to your endpoint URL — a form-to-email provider's URL, your own API route, or omit it if JavaScript will handle the request instead.

Step 3: If you want a page reload after submission (simplest, works with JavaScript disabled), leave the browser's default behavior in place. If you want an inline success message with no reload, intercept submit and call preventDefault().

Step 4: Test the actual network request in your browser's DevTools Network tab — confirm the method and destination match what you configured, and check the response status.


Common Mistakes

Leaving method unset and getting GET by default. Covered above — check every form's method attribute is explicitly POST unless it's genuinely a search/filter form.

Sensitive data in a GET form. Never use GET for anything containing an email address, name, message, or any personal data — it ends up in browser history, server logs, and can leak via the Referer header to any third-party resource the destination page loads.

Forgetting name attributes. action and method can be perfectly correct and the form will still submit nothing useful if fields lack name — the browser only sends named fields.

Assuming action-less forms do nothing. They submit to the current URL, which for a server-rendered page can trigger real (if silent) server-side behavior — don't assume an empty action is a no-op.

Mixing a JavaScript fetch submission with a type="submit" button and no preventDefault(). The browser's native navigation and your fetch call both fire, usually causing the page to navigate away before the fetch response is ever handled.


Best Practices

  • Default to POST unless you specifically need a shareable/bookmarkable URL state, which is rare outside search and filter UIs.

  • Always set method explicitly rather than relying on the GET default — it documents intent and avoids the most common silent-failure bug.

  • Keep a method="POST" fallback on the <form> tag even for JavaScript-handled submissions, so the form still does something reasonable if a script fails to load.

  • Never put personal or sensitive data in a GET form.

  • Test with JavaScript disabled if you support progressive enhancement — a form relying entirely on a submit event listener does nothing at all without it.


The Developer Tools category has the rest of the HTML form utilities.


FAQ

Can I use PUT or DELETE as a form method?

No — the HTML method attribute only supports GET and POST natively. PUT, DELETE, and other HTTP methods require JavaScript (fetch with the method explicitly set) rather than the form tag's own attribute.

What happens if action points to a URL on a different domain?

The browser submits cross-origin exactly as it would same-origin for a plain HTML form submission — no CORS restriction applies to a native form navigation. CORS only becomes relevant when you submit via JavaScript's fetch/XMLHttpRequest, where the destination server must explicitly allow your origin.

Why does my GET form show query parameters even for empty fields?

Every named field submits, including empty ones — an empty text input still appends name= to the query string. Filter empty fields server-side if you don't want them in the URL, or in JavaScript before building a fetch request.

Is method="POST" enough to keep form data private?

It keeps data out of the URL and browser history, which GET does not — but the data is still visible to anyone who can inspect network traffic (use HTTPS to encrypt it in transit) and to whatever server ultimately receives it. POST alone doesn't make data confidential from the receiving server.

Do I need enctype for a form with a file upload?

Yes — add enctype="multipart/form-data" alongside method="POST" for any form containing a type="file" input, or the file's contents won't be included in the submission at all.


Build a Correctly-Configured Form Now

Form Studio sets action and method (or the equivalent fetch call) based on the delivery method you choose in the Delivery tab — free, and it runs entirely in your browser.

Khushbu

Khushbu

Full-Stack Developer & Founder

I build tools I wish existed — fast, free, and private. Every tool runs in your browser because I believe your data should stay yours.