Framework Integrations
Copy-paste examples to connect Formtorch to Next.js, React, Vue, Astro, and plain HTML.
Replace https://formtorch.com/f/abc123 with your real endpoint from the Formtorch dashboard.
HTML
No-frameworkThe simplest integration — point a standard HTML form's action attribute at your Formtorch endpoint. No JavaScript required for basic submissions.
A plain HTML form that submits via a full-page POST.
<form
action="https://formtorch.com/f/abc123"
method="POST"
>
<input type="text" name="name" placeholder="Name" required />
<input type="email" name="email" placeholder="Email" required />
<textarea name="message" placeholder="Message"></textarea>
<button type="submit">Send message</button>
</form>Next.js
App RouterThree patterns for Next.js App Router: a client component with fetch, a server action that runs on the server, and a lightweight API route handler.
A 'use client' form component that posts to Formtorch via fetch.
'use client';
import { useState } from 'react';
export default function ContactForm() {
const [status, setStatus] = useState<
'idle' | 'sending' | 'done'
>('idle');
async function handleSubmit(
e: React.FormEvent<HTMLFormElement>
) {
e.preventDefault();
setStatus('sending');
const res = await fetch('https://formtorch.com/f/abc123', {
method: 'POST',
headers: { 'X-Requested-With': 'XMLHttpRequest' },
body: new FormData(e.currentTarget),
});
setStatus(res.ok ? 'done' : 'idle');
}
if (status === 'done') {
return <p>Thanks! We will be in touch.</p>;
}
return (
<form onSubmit={handleSubmit}>
<input name="name" placeholder="Name" required />
<input name="email" type="email" placeholder="Email" required />
<textarea name="message" placeholder="Message" />
<button type="submit" disabled={status === 'sending'}>
{status === 'sending' ? 'Sending...' : 'Send message'}
</button>
</form>
);
}React
Client-sideTwo approaches for React: controlled inputs with a JSON payload, and uncontrolled inputs using the native FormData API.
Manage input state with useState and POST as JSON.
import { useState } from 'react';
type Fields = { name: string; email: string; message: string };
export function ContactForm() {
const [fields, setFields] = useState<Fields>({
name: '', email: '', message: '',
});
const [sent, setSent] = useState(false);
function set(
e: React.ChangeEvent<
HTMLInputElement | HTMLTextAreaElement
>
) {
setFields((f) => ({ ...f, [e.target.name]: e.target.value }));
}
async function handleSubmit(e: React.FormEvent) {
e.preventDefault();
await fetch('https://formtorch.com/f/abc123', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Requested-With': 'XMLHttpRequest',
},
body: JSON.stringify(fields),
});
setSent(true);
}
if (sent) return <p>Thanks! We will be in touch.</p>;
return (
<form onSubmit={handleSubmit}>
<input name="name" value={fields.name} onChange={set} required />
<input
name="email"
type="email"
value={fields.email}
onChange={set}
required
/>
<textarea
name="message"
value={fields.message}
onChange={set}
/>
<button type="submit">Send</button>
</form>
);
}Astro
Static siteAstro renders to static HTML, so a plain form with an action attribute works out of the box — no JavaScript island required.
Drop a standard HTML form into any .astro file.
---
// src/pages/contact.astro
---
<form
action="https://formtorch.com/f/abc123"
method="POST"
>
<input type="text" name="name" placeholder="Name" required />
<input type="email" name="email" placeholder="Email" required />
<textarea name="message" placeholder="Message"></textarea>
<button type="submit">Send message</button>
</form>Vue
Client-sideA single-file component using v-model for reactive input binding and @submit.prevent for AJAX submission.
v-model bindings with a Fetch POST on submit.
<template>
<div v-if="sent">
<p>Thanks! Message sent.</p>
</div>
<form v-else @submit.prevent="handleSubmit">
<input
v-model="name"
name="name"
placeholder="Name"
required
/>
<input
v-model="email"
type="email"
name="email"
placeholder="Email"
required
/>
<textarea
v-model="message"
name="message"
placeholder="Message"
></textarea>
<button type="submit" :disabled="sending">
{{ sending ? 'Sending...' : 'Send message' }}
</button>
</form>
</template>
<script setup>
import { ref } from 'vue';
const name = ref('');
const email = ref('');
const message = ref('');
const sending = ref(false);
const sent = ref(false);
async function handleSubmit() {
sending.value = true;
await fetch('https://formtorch.com/f/abc123', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
name: name.value,
email: email.value,
message: message.value,
}),
});
sent.value = true;
}
</script>SvelteKit
Client-sideUse Svelte reactive variables with bind:value and on:submit for a clean, minimal integration.
bind:value reactive inputs with on:submit|preventDefault.
<script lang="ts">
let name = '';
let email = '';
let message = '';
let sent = false;
async function handleSubmit() {
await fetch('https://formtorch.com/f/abc123', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name, email, message }),
});
sent = true;
}
</script>
{#if sent}
<p>Thanks! Message sent.</p>
{:else}
<form on:submit|preventDefault={handleSubmit}>
<input
bind:value={name}
name="name"
placeholder="Name"
required
/>
<input
bind:value={email}
type="email"
name="email"
placeholder="Email"
required
/>
<textarea
bind:value={message}
name="message"
placeholder="Message"
></textarea>
<button type="submit">Send message</button>
</form>
{/if}Gatsby
Client-sideGatsby is built on React, so the same hooks-based pattern applies. Submit with FormData for the simplest integration.
A standard React form component using FormData and fetch.
import React, { useState } from 'react';
export default function ContactForm() {
const [sent, setSent] = useState(false);
async function handleSubmit(e) {
e.preventDefault();
await fetch('https://formtorch.com/f/abc123', {
method: 'POST',
headers: { 'X-Requested-With': 'XMLHttpRequest' },
body: new FormData(e.target),
});
setSent(true);
}
if (sent) return <p>Thanks! Message sent.</p>;
return (
<form onSubmit={handleSubmit}>
<input name="name" placeholder="Name" required />
<input
name="email"
type="email"
placeholder="Email"
required
/>
<textarea name="message" placeholder="Message" />
<button type="submit">Send message</button>
</form>
);
}Webflow
No-codeAdd a Formtorch-powered form to any Webflow project using an HTML Embed element. No custom code editor access required.
Paste this into a Webflow HTML Embed block on any page.
<!-- Paste into a Webflow HTML Embed element -->
<form
action="https://formtorch.com/f/abc123"
method="POST"
>
<input type="text" name="name" placeholder="Name" required />
<input type="email" name="email" placeholder="Email" required />
<textarea name="message" placeholder="Message"></textarea>
<button type="submit">Send message</button>
</form>Ship forms without maintaining a backend
Create an endpoint, paste it into your form, and start receiving submissions.