Skip to content
FormclickDocs
HTML FormsSubmitting

React, Next.js & Vue

Copy-paste contact forms for React, Next.js and Vue.

Formclick has no SDK to install. In a framework you either render a plain HTML form, or post JSON with fetch and keep the state in your component.

ContactForm.jsx
import { useState } from 'react';

export default function ContactForm() {
  const [status, setStatus] = useState('idle'); // idle | sending | sent | error
  const [error, setError] = useState('');

  async function onSubmit(e) {
    e.preventDefault();
    setStatus('sending');
    const data = Object.fromEntries(new FormData(e.currentTarget));

    const res = await fetch('https://api.formclick.io/submit', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json', Accept: 'application/json' },
      body: JSON.stringify({ access_key: process.env.NEXT_PUBLIC_FORMCLICK_KEY, ...data }),
    });
    const result = await res.json();

    if (result.success) {
      setStatus('sent');
      e.target.reset();
    } else {
      setStatus('error');
      setError(result.message);
    }
  }

  if (status === 'sent') return <p>Thanks! We'll be in touch soon.</p>;

  return (
    <form onSubmit={onSubmit}>
      <input name="name" placeholder="Name" required />
      <input name="email" type="email" placeholder="Email" required />
      <textarea name="message" placeholder="Message" required />
      <input type="checkbox" name="botcheck" style={{ display: 'none' }} tabIndex={-1} />
      <button disabled={status === 'sending'}>
        {status === 'sending' ? 'Sending…' : 'Send'}
      </button>
      {status === 'error' && <p role="alert">{error}</p>}
    </form>
  );
}

Keeping the key in an environment variable

The access key is public, so an env variable is about convenience rather than secrecy: one key per environment, nothing hard-coded. Next.js exposes variables prefixed with NEXT_PUBLIC_; Vite uses VITE_.

.env.local
NEXT_PUBLIC_FORMCLICK_KEY=YOUR_ACCESS_KEY

Using formclick.min.js in a framework

Plain HTML forms in a framework (like the Next.js example above) should load the script too. Load it once in your root layout and it enhances forms as they are rendered, including on client-side navigation.

app/layout.tsx
import Script from 'next/script';

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body>
        {children}
        {/* Handles submit, file upload, loading state and success/error messages. */}
        <Script src="https://cdn.formclick.io/formclick.min.js" strategy="afterInteractive" />
      </body>
    </html>
  );
}
Still need help? Contact support or email support@formclick.io.