Contact form html in full: the code for contact form pages, the contact form html code worth pasting, contact forms html done properly, and how to create a contact form in html from nothing

A contact form is four elements and two attributes, and almost every version of it on the web gets one of them slightly wrong. The markup itself is genuinely small: a form, a label and a control for each thing you want to know, and a button. What takes the time is the part that is not markup at all, which is deciding where the browser sends the submission and what answers it. Here is the whole of the first part, and an honest account of the second.

The form element, and the two attributes that matter

Everything hangs off the opening tag. method="post" sends the values in the request body rather than the URL, which keeps a message out of browser history, out of your access logs and out of the referrer header the next page sends. action is the URL the browser posts to. Leave it out and the form posts back to the page it is on, which is fine if something there can receive it and useless on a static host, because a static host serves files and cannot answer a POST. If you have ever wondered why a copied snippet did nothing when you pressed send, this attribute is almost always the reason.

A label for every control, bound with for and id

Each control needs its own label element with a for attribute matching the control's id. That binding is what lets a screen reader announce the field, and it is also what makes the label clickable, which quietly widens the target on a phone. A placeholder is not a label: it vanishes the instant somebody starts typing, which is the exact moment they are most likely to have forgotten what the field was for. Use the input type that matches the answer, so an address is type="email" and a message is a textarea rather than a very long text input, and give every control a name attribute, because a control without a name is not submitted at all.

What required actually promises

Adding required to a control makes the browser refuse to submit while it is empty and show a message next to it, with no round trip and no JavaScript. That is a real improvement for the person filling the form in, and it is not a rule you can rely on. The browser belongs to them, not to you: developer tools can remove the attribute in a second, and nothing stops a script posting whatever it likes straight at your action URL. Treat every constraint attribute as a courtesy that saves a round trip, and check the same things again wherever the submission actually lands.

Where the submission goes on a static site

This is the part the snippets skip. If your page is served from object storage or a static host, there is no process at your domain to receive a POST, so the action has to point somewhere that can: a serverless function you write and deploy, a small server of your own, or a hosted endpoint built for exactly this. Whichever you choose, it has to do three things: validate the submission again, do something durable with it so it is not only an email that can be lost, and reply with a page a human can read, because the browser will render whatever comes back.

Questions people ask about contact form html

Can I write a contact form with no JavaScript at all?

Yes, and it is the better starting point. A plain form posts, the browser navigates, and the page that answers confirms it. JavaScript is worth adding afterwards if you want to submit without leaving the page, but a form that only works once a script has loaded is a form that fails quietly for anyone whose script did not.

Should the action point at a mailto: address?

No. A mailto action hands the submission to whatever mail client the person has configured, which on plenty of machines is nothing at all, and when it does work it opens a half-filled draft they still have to send themselves. It also puts your address in the page for every scraper to collect. Post to a URL that accepts the request instead.

Do I need a name attribute on every field?

On every field you want to receive, yes. The name is the key the value arrives under, so a control without one is simply not part of the submission. It is the most common reason a field that looks right on the page never turns up on the other end.

Sources

Related answers

Get an endpoint for this formPoint this form at Endpointo