React (@frontmail/react)
npm install @frontmail/reactWorks with React 18 and 19, including Next.js (use it in client components).
Provider
Section titled “Provider”Wrap your app (or just the part with forms) in FrontmailProvider. Keep the options object stable
– define it at module level or with useMemo:
import { FrontmailProvider } from '@frontmail/react';
const frontmailOptions = { publicKey: 'pk_4f2a…', blockHeadless: true };
export function App() { return ( <FrontmailProvider options={frontmailOptions}> <Routes /> </FrontmailProvider> );}options accepts everything init() does. Alternatively, pass an
existing client: <FrontmailProvider client={client}>.
FrontmailForm
Section titled “FrontmailForm”The fastest way to a working form – it submits via sendForm, renders Turnstile when you pass a
site key and exposes the send state:
import { FrontmailForm } from '@frontmail/react';
export function ContactForm() { return ( <FrontmailForm serviceId="svc_01J9…" templateId="tpl_contact" turnstileSiteKey="YOUR_TURNSTILE_SITE_KEY" onSuccess={(result) => console.log(result.status)} onError={(error) => console.error(error.code)} > {({ status, error }) => ( <> <input name="name" required /> <input name="email" type="email" required /> <textarea name="message" required /> <button disabled={status === 'sending'}>Send</button> {status === 'sent' && <p>Thank you!</p>} {status === 'held' && <p>Received – it will be delivered shortly.</p>} {error && <p role="alert">{error.message}</p>} </> )} </FrontmailForm> );}Props: serviceId, templateId, turnstileSiteKey, turnstileOptions, sendOptions,
resetOnSuccess (default true), onSuccess, onError, plus any <form> attribute. Children
can be nodes or a function of the state { status, error, result }.
turnstileSiteKey is the site key of your own Turnstile widget (Security → Bot protection
(Turnstile) in the dashboard) – see Cloudflare Turnstile. Leave it out if the
template doesn’t require a CAPTCHA.
useSendEmail
Section titled “useSendEmail”For custom UIs and controlled forms:
import { useState } from 'react';import { useSendEmail } from '@frontmail/react';
function Newsletter() { const { send, status, error, reset } = useSendEmail('svc_01J9…', 'tpl_newsletter'); const [email, setEmail] = useState('');
return ( <form onSubmit={async (e) => { e.preventDefault(); await send({ email }); }}> <input value={email} onChange={(e) => setEmail(e.target.value)} /> <button disabled={status === 'sending'}>Subscribe</button> {status === 'error' && <p role="alert">{error?.message}</p>} </form> );}status is idle → sending → sent | held | error. send() and sendForm() resolve with
the result or undefined on error (the error is in error), so you don’t need try/catch.
useFrontmail
Section titled “useFrontmail”Returns the client from the provider for anything else, e.g. getStatus:
import { useFrontmail } from '@frontmail/react';
const client = useFrontmail();const status = await client.getStatus(messageId, { token });Typed params
Section titled “Typed params”With generated types, useSendEmail('svc_…', 'tpl_contact').send({...})
type-checks the params of that template.
Example project: examples/react.