Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
166 changes: 166 additions & 0 deletions craft-freeform/headless/getting-started.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
---
title: Getting Started
sidebar_position: 1
description: Install and enable Freeform's official headless React packages for Craft CMS.
---

import { Badge, BadgeGroup } from '@site/src/components/utils';
import { VerticalStepWrapper, StepMarkdown } from '@site/src/components/docs';

# Getting Started (React Headless)<BadgeGroup><Badge type="lite" text="Lite" /><Badge type="pro" text="Pro" /></BadgeGroup>

Freeform’s recommended headless path for React and Next.js 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 (`0.1.0`)
4. Render forms with `<Freeform />` or build your own UI with `useFreeform()`

GraphQL and older AJAX demos remain available, but new React/Next.js projects should start here.

:::tip Example app
Clone the [Freeform Headless React Demo](https://github.com/solspace/freeform-headless-react-demo) to try the packages against your Craft site.
:::

## Requirements

| Piece | Version / notes |
| --- | --- |
| Craft CMS | 4.17+ or 5.9+ |
| Freeform plugin | Build that includes headless REST |
| npm packages | **`0.1.0`** ([npm org](https://www.npmjs.com/org/solspace)) |
| React | 18 or 19 |
| Node | Modern LTS with `npm` / `pnpm` / `yarn` |

## Quick setup

<VerticalStepWrapper>
<StepMarkdown stepTitle="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 / Next.js app repo.

Edit or create:

```text
your-craft-project/config/freeform.php
```

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

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

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

```php title="config/freeform.php" showLineNumbers
<?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,
],
],
],
];
```

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

See the full [REST API](./rest-api.mdx) reference for profiles, CSRF, and submit details.

</StepMarkdown>
<StepMarkdown stepTitle="Install the npm packages">

```bash
npm install @solspace/freeform-core \
@solspace/freeform-react \
@solspace/freeform-extensions \
@solspace/freeform-react-theme-default
```

| Package | Purpose |
| --- | --- |
| `@solspace/freeform-core` | Manifest client, form state, conditionals, submit |
| `@solspace/freeform-react` | `<Freeform />` component and `useFreeform()` hook |
| `@solspace/freeform-extensions` | Captchas, datetime picker, file drag & drop |
| `@solspace/freeform-react-theme-default` | Default light/dark theme CSS |

</StepMarkdown>
<StepMarkdown stepTitle="Render a form">

```tsx title="ContactForm.tsx" showLineNumbers
import { Freeform } from '@solspace/freeform-react';
import { recommendedExtensions } from '@solspace/freeform-extensions';
import '@solspace/freeform-react-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

</StepMarkdown>
</VerticalStepWrapper>

## Choose your guide

| Guide | When to use it |
| --- | --- |
| [React JS](./reactjs.mdx) | Vite, CRA, Remix, or any React SPA |
| [Next.js](./nextjs.mdx) | App Router / Pages Router + proxy |
| [REST API](./rest-api.mdx) | Endpoints, CSRF, CORS, profiles |
| [GraphQL](./graphql.mdx) | Existing GraphQL integrations (alternate path) |
| [Example demo](https://github.com/solspace/freeform-headless-react-demo) | Cloneable Vite app using the published packages |

## 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
- Default theme with light / dark / system color schemes

## Coming later

- Drafts / save & continue
- Payment fields (Stripe, etc.)
- Calculation fields
- Official Vue adapter
- Bootstrap and Tailwind theme packages
- Full GraphQL parity with the REST contract

## 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.
6 changes: 5 additions & 1 deletion craft-freeform/headless/graphql.mdx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: GraphQL
sidebar_position: 1
sidebar_position: 6
description: Integrate Freeform 5.x with GraphQL in Craft CMS for headless form handling and submissions.
---

Expand All @@ -14,6 +14,10 @@ import { VerticalStepWrapper, StepMarkdown } from '@site/src/components/docs';

Freeform supports querying form layouts and form submission mutations via GraphQL. This guide assumes you have some GraphQL experience. To learn more about GraphQL and Craft, please check out the [Fetch content with GraphQL](https://craftcms.com/docs/getting-started-tutorial/build/graphql.html) guide and [Craft's GraphQL API](https://craftcms.com/docs/5.x/development/graphql.html).

:::tip New React / Next.js projects
For new React and Next.js apps, prefer the official packages and [REST API](./rest-api.mdx) — start with [Getting Started](./getting-started.mdx). GraphQL remains fully supported for existing headless integrations.
:::

<Photo
img={require('@site/static/img/craft/freeform/v5/cp/graphql.png')}
alt="GraphQL"
Expand Down
37 changes: 29 additions & 8 deletions craft-freeform/headless/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -4,34 +4,55 @@ import Icons from '@site/static/icons/cards';

# Headless

Freeform supports headless website architecture making it easy to use JavaScript-based front-end frameworks such as Vue.js, Next.js, React JS and more! Freeform also supports querying form layouts and using mutations to create submissions via GraphQL.
Freeform supports headless website architecture for JavaScript front ends such as React, Next.js, and Vue.js.

**Recommended for new React / Next.js projects:** the official npm packages (`0.1.0`) and the headless REST API. GraphQL remains available for existing integrations.

Start with [Getting Started](./getting-started) to enable headless and install `@solspace/freeform-react`, or try the [example React demo](https://github.com/solspace/freeform-headless-react-demo).

<FlexCards
navCards
items={[
{
title: 'Vue.js',
description: 'Full support for implementation Freeform with Vue.js.',
icon: Icons.VuejsIcon,
fullCardLink: 'vuejs',
title: 'Getting Started',
description:
'Enable the headless API and install the official React packages.',
icon: Icons.HeadlessIcon,
fullCardLink: 'getting-started',
},
{
title: 'REST API',
description:
'Manifest, submit, CSRF, CORS, and file upload endpoints.',
icon: Icons.ApiGearIcon,
fullCardLink: 'rest-api',
},
{
title: 'React JS',
description: 'Full support for implementation Freeform with React JS.',
description:
'Render forms with <Freeform /> or build your own UI with useFreeform().',
icon: Icons.ReactIcon,
fullCardLink: 'reactjs',
},
{
title: 'Next.js',
description: 'Full support for implementation Freeform with Next.js.',
description:
'App Router Client Components, rewrites proxy, and CSRF-friendly setup.',
icon: Icons.NextjsIcon,
fullCardLink: 'nextjs',
filterIcon: true,
},
{
title: 'Vue.js',
description:
'Headless demos for Vue.js (official Vue package coming later).',
icon: Icons.VuejsIcon,
fullCardLink: 'vuejs',
},
{
title: 'GraphQL',
description:
'With Freeform, you can easily query form layouts and submit form mutations using GraphQL.',
'Query form layouts and create submissions with GraphQL mutations.',
icon: Icons.GraphqlIcon,
fullCardLink: 'graphql',
},
Expand Down
Loading