Skip to main content

Getting Started (Headless)
LitePro
Improved in 5.16+

Freeform's recommended headless path for React, Next.js, and Vue is:

  1. Use a Freeform plugin build that includes the headless REST API
  2. Enable headless in Freeform config
  3. Install the official npm packages
  4. Render forms with <Freeform /> or build your own UI with useFreeform()

GraphQL and older AJAX demos remain available, but new projects should start here.

Clone the Freeform Headless React Demo, Vue Demo, or Nuxt Demo to try the packages against your Craft site (REST, GraphQL tab, Save & Continue, table, signature, calculation, payments, and more).

Requirements

PieceVersion / notes
Craft CMS4.17+ or 5.9+
Freeform plugin5.16+
npm packagesOfficial @solspace/freeform-* packages (npm org)
React18 or 19 (for @solspace/freeform-react)
Vue3.4+ (for @solspace/freeform-vue)
NodeModern LTS with npm / pnpm / yarn

Quick setup

1

Enable headless in Freeform (Craft project)

Headless is off by default. Configure it in your Craft CMS project (the site where Freeform is installed) — not in your React / Vue / Next.js app repo.

Edit or create:

your-craft-project/config/freeform.php

That file lives next to Craft's other config files (general.php, routes.php, etc.), for example:

~/Sites/my-craft-site/config/freeform.php

Merge a headless section into that file (keep any existing Freeform settings):

config/freeform.php
<?php

return [
'headless' => [
// Master switch — endpoints return 404 when false
'enabled' => true,

// CORS origins for browser apps that call Craft directly
'allowedOrigins' => [
'http://localhost:3000',
'https://app.example.com',
],

// Per-form exposure (keyed by form handle from the Freeform CP)
'forms' => [
'contact' => [
'exposeManifest' => true,
'allowSubmit' => true,
],
],
],
];

If your frontend proxies /freeform/* to Craft (recommended for Next.js and SPAs), CSRF cookies stay same-origin and you can keep allowedOrigins tight.

See the full REST API reference for profiles, CSRF, and submit details.

2

Install the npm packages

npm install @solspace/freeform-core \
@solspace/freeform-react \
@solspace/freeform-extensions \
@solspace/freeform-theme-default
PackagePurpose
@solspace/freeform-coreManifest client, form state, conditionals, submit
@solspace/freeform-reactReact <Freeform /> and useFreeform() hook
@solspace/freeform-vueVue <Freeform /> and useFreeform() composable
@solspace/freeform-extensionsCaptchas, datetime, file drag & drop, calculation, table, signature, Stripe, Square, PayPal, and Mollie payments
@solspace/freeform-theme-defaultDefault light/dark theme CSS (React & Vue)
@solspace/freeform-theme-tailwindOfficial Tailwind starter theme (class maps)
@solspace/freeform-theme-bootstrapOfficial Bootstrap 5 starter theme (class maps)
3

Render a form

ContactForm.tsx
import { Freeform } from '@solspace/freeform-react';
import { recommendedExtensions } from '@solspace/freeform-extensions';
import '@solspace/freeform-theme-default/styles.css';

export function ContactForm() {
return (
<Freeform
handle="contact"
baseUrl="https://cms.example.com"
extensions={recommendedExtensions}
onSuccess={(response) => {
console.log('Submitted', response);
}}
/>
);
}
  • handle — Freeform form handle (must be enabled under headless.forms)
  • baseUrl — Craft site origin, or "" / same origin when you proxy /freeform
  • extensions — register captchas and advanced fields when the form needs them

Choose your guide

GuideWhen to use it
React JSVite, CRA, Remix, or any React SPA
Next.jsApp Router / Pages Router + proxy
Vue.jsVite or any Vue 3 app
NuxtNuxt 3 / 4 + client-only Freeform + proxy
REST APIEndpoints, CSRF, CORS, profiles
GraphQLHeadless adapters (freeformHeadlessManifest / freeformHeadlessSubmit) or legacy form GraphQL
React demoCloneable Vite + React app
Vue demoCloneable Vite + Vue app
Nuxt demoCloneable Nuxt 3 app

What's included

  • Manifest load + CSRF + submit (JSON and multipart)
  • Multi-page forms and conditionals (client UX)
  • Captchas via @solspace/freeform-extensions
  • File upload and File Drag & Drop
  • Save & Continue Later (draft token + key; see React JS / Vue.js)
  • Calculation fields
  • Table fields (row limits, required columns, file cells)
  • Signature fields (canvas pad + clear)
  • Stripe payments (Payment Element; see React JS → Stripe / Vue.js → Payments)
  • Square payments (Web Payments SDK; see React JS → Square / Vue.js → Payments)
  • PayPal payments (Buttons; see React JS → PayPal / Vue.js → Payments)
  • Mollie payments (hosted checkout redirect; see React JS → Mollie / Vue.js → Payments)
  • Default theme with light / dark / system color schemes
  • Official Tailwind starter theme (@solspace/freeform-theme-tailwind)
  • Official Bootstrap 5 starter theme (@solspace/freeform-theme-bootstrap)
  • Headless GraphQL adapters (freeformHeadlessManifest / freeformHeadlessSubmit)

Security checklist

  1. Keep headless disabled until you intentionally enable forms.
  2. Set explicit headless.allowedOrigins for cross-origin apps.
  3. Enable a captcha on public forms (do not rely on honeypot alone for API callers).
  4. Leave allowRawHtml off unless HTML / rich-text field content is trusted CMS content.
  5. Do not treat client-side conditional hiding as a server access-control boundary yet.