A static site that collects form submissions, in one HTML attribute
A static site has no backend. That is the point of one - and it is also why the contact form is the first thing that breaks. The usual answers are a third-party form service with its own signup, a serverless function you now maintain, or a mailto: link nobody clicks. There is a third option that falls out of how static hosting already works: the host is in the path of every HTML response it serves. It can collect the form itself. On harvis.dev that is one attribute: Send Deploy, and submissions show up in the dashboard. No script tag, no API key in the page, no fetch() , no JavaScript at all - the form works with JS disabled, because it is a plain HTML form doing what plain HTML forms have always done. The page I am describing is live at harvis-forms-example.harvis.dev - submit the form and see where you land. Everything below is what makes that page work. What actually happens The rewrite happens on the way out, while the HTML is being served: - action andmethod are replaced with/harvis/form/contact on your site's own subdomain. Same origin, so there is no CORS, no preflight, and nothing in the page has to know a project id. - A honeypot field is inserted. It is positioned off-screen rather than display: none , because a bot that skips hidden inputs is a bot that would otherwise get through. Anything that fills it in gets the success page and is stored nowhere - a bot that can tell it was caught is a bot that tries again differently. - data-harvis-redirect="/thanks.html" becomes a hidden field, since the handler never sees your HTML - only what the browser posts. It is re-validated on arrival, and a protocol-relative//somewhere-else is refused. The reply is a 303, so the browser follows it with a GET and a refresh on the thank-you page cannot post the form twice. The form name is part of a URL and a dashboard heading, so it has to match [a-z0-9][a-z0-9-]{0,39} . Anything else - including a bare harvis-form with no value - collects under default . Two forms on one page, two named inboxes: โฆ โฆ The second one has no redirect, so it lands on a branded thank-you page the host serves. The one case where the attribute does nothing The rewrite runs over the response body, so it only sees markup that is already in the file. A form that React, Vue or Svelte mounts at runtime has no in the served HTML - the marker never matches and nothing is rewritten. Write the endpoint yourself instead: {/* โฆyour fieldsโฆ */} The receiving side does not care who wrote those fields. Drop the harvis-form attribute when you do this, or a prerendered page gets rewritten twice and ends up with two honeypots. Try it The page: https://harvis-forms-example.harvis.dev/ The complete source - two forms, the deploy script, the workflow - is here: https://github.com/harvis-io/solutions/tree/main/forms-example Three files of site, no build step, no dependencies. Clone it, run HARVIS_API_KEY=hvsโฆ ./deploy.sh public , and you have a static page with a working contact form about two seconds later. Here is the served HTML of that live page, which is the shortest version of this whole post: Top comments (0)
Comments
No comments yet. Start the discussion.