Visual drag-and-drop form builder for Strapi 5. Create, publish and embed forms on any website.
released July 10, 2026
npm install strapi-plugin-form-builder-cmsA visual drag-and-drop form builder plugin for Strapi 5. Create, publish and embed forms on any website without writing a single line of backend code.
/api/strapi-plugin-form-builder-cms/page/:slug (available once the form is published).<script> tag renders the form on any external site with zero dependencies.| Dependency | Version |
|---|---|
| Strapi | ^5.0.0 |
| Node.js | >=18.0.0 |
| React | ^18.0.0 |
# npm
npm install strapi-plugin-form-builder-cms
# yarn
yarn add strapi-plugin-form-builder-cmsAdd the plugin to your Strapi configuration:
// config/plugins.js (or config/plugins.ts)
module.exports = {
'strapi-plugin-form-builder-cms': {
enabled: true,
},
};npm run build
npm run developThe Form Builder entry will appear in the Strapi admin sidebar.
Open the form and click the Embed button to copy the snippet:
<div id="sfb-form-{id}"></div>
<script
src="https://your-strapi-domain.com/api/strapi-plugin-form-builder-cms/embed.js"
data-form-id="{id}"
async
></script>Paste both tags wherever you want the form to appear. The script is self-contained — no external dependencies, no build step required.
Toggle Public page in the form settings drawer and publish the form. A shareable URL is generated:
https://your-strapi-domain.com/api/strapi-plugin-form-builder-cms/page/{slug}Share or link directly to this page — it renders the form in a clean, responsive layout served by Strapi itself.
The public page, embed and submit endpoint only serve published forms. An unpublished (draft) form returns
404.
Click Submissions on any form from the list page. Search, filter by status, and pick which columns to show. Open a submission for a detail drawer with next/previous navigation; mark as read, archive or delete — individually or in bulk. Export everything to CSV.
These routes require no authentication and are safe to call from the browser.
| Method | Path | Description |
|---|---|---|
GET | /api/strapi-plugin-form-builder-cms/embed.js | Serve the embed script |
GET | /api/strapi-plugin-form-builder-cms/forms/:id/embed-schema | Form schema by numeric ID |
GET | /api/strapi-plugin-form-builder-cms/forms/:slug/schema | Form schema by slug |
GET | /api/strapi-plugin-form-builder-cms/page/:slug | Hosted public page |
POST | /api/strapi-plugin-form-builder-cms/forms/:slug/submit | Submit form data |
{
"data": {
"fieldName": "value",
"checkboxGroupField": ["option1", "option2"]
}
}{ "success": true, "successMessage": "Thank you!" }400){
"success": false,
"errors": {
"email": ["Enter a valid email address"],
"name": ["Minimum 3 characters"]
}
}400) or rate limit (429){ "success": false, "message": "Captcha verification failed. Please try again." }| Type | Description |
|---|---|
text | Single-line text input |
email | Email input (auto-validates format) |
number | Numeric input (auto-validates format) |
phone | Tel input |
url | URL input (auto-validates format) |
password | Password input |
date | Date picker |
time | Time picker |
textarea | Multi-line text |
select | Dropdown — configure options in the settings panel |
radio | Radio group — configure options in the settings panel |
checkbox | Single checkbox (agree / consent) |
checkbox-group | Multiple checkboxes — configure options in the settings panel |
hidden | Invisible tracking field — prefilled from a URL query parameter (e.g. utm_source) or a default value, then stored with the submission |
heading | Non-input heading label |
paragraph | Non-input descriptive text |
divider | Horizontal rule to separate sections |
| Rule | Applies to | Description |
|---|---|---|
required | All input fields | Field must not be empty |
minLength | Text fields | Minimum character count |
maxLength | Text fields | Maximum character count |
min | number | Minimum numeric value |
max | number | Maximum numeric value |
email | Text fields | Must be a valid email address |
url | Text fields | Must be a valid URL |
pattern | Text fields | Must match a regular expression |
Each rule accepts an optional custom error message. The same rule type cannot be added twice to the same field.
| Setting | Description |
|---|---|
| Description | Optional intro text shown above the form |
| Submit button text | Label on the submit button |
| Success message | Message shown after a successful submission |
| Public page | Generates a hosted page URL for the form (served once published) |
| Honeypot protection | Adds a hidden field to silently discard bot submissions |
| Rate limiting | Caps submissions per IP each hour (configurable max) |
| CAPTCHA | None, Cloudflare Turnstile or Google reCAPTCHA v2 — with a Test secret key button to validate credentials before publishing |
| Custom styles | Enables the visual Style editor for the form (see below) |
| Redirect URL | Where to send the visitor after a successful submit |
Protect a form with a human-verification challenge. In the form settings drawer, under Spam & limits → CAPTCHA, pick a provider and paste your keys:
| Provider | Where to get keys |
|---|---|
| Cloudflare Turnstile | Turnstile dashboard |
| Google reCAPTCHA v2 | reCAPTCHA admin console |
400, even if the client is bypassed.The public page relaxes its Content-Security-Policy just enough to load the chosen provider's script and iframe — only when a CAPTCHA is configured.
Add a hidden field to capture campaign data into every submission without showing anything to the visitor:
utm_source).?utm_source=google, that value is captured automatically.The captured value is stored with the submission and included in the CSV export.
Turn on Custom styles in the form's Settings drawer to reveal a Style tab next to Fields. It opens a dedicated editor with a live Desktop/Mobile preview:
Everything resolves to a small set of --sfb-* CSS variables applied to both the preview and the public form, so the preview matches production. Style changes follow the normal draft / publish flow — they go live when you publish.
The embedded form renders in the host page's DOM (no shadow DOM), so you can also restyle it from your own site.
CSS variables (the recommended, stable API):
#sfb-form-1 { /* the container div, or any ancestor */
--sfb-accent: #e11d48;
--sfb-radius: 12px;
}Or target the classes directly — .sfb-form, .sfb-field, .sfb-label, .sfb-input, .sfb-btn, .sfb-help, .sfb-error, .sfb-success. The plugin's rules use single-class specificity; to reliably win, scope your selector to the form container:
#sfb-form-1 .sfb-input { border-width: 2px; }Per-field class — give any field a CSS class in its settings panel (e.g. newsletter-email). It's added to that field's wrapper, so you can style one field from your own stylesheet:
.newsletter-email input { border-color: #e11d48; }
.newsletter-email .sfb-label { font-weight: 700; }The class sits on the field's wrapper (not the <input>), so a descendant selector like .newsletter-email input naturally out-specifies the plugin's own rules — no !important needed.
Clone the repo and link the plugin to a local Strapi project:
git clone https://github.com/devCluna/strapi-plugin-form-builder-cms.git
cd strapi-plugin-form-builder-cms
npm install
# watch mode — rebuilds on save
npm run watch:linkIn your local Strapi project:
npm run developRun the test suite (Vitest) and type-checks:
npm test # unit tests
npm run test:ts:back # type-check the server
npm run test:ts:front # type-check the adminPull requests are welcome. For major changes please open an issue first to discuss what you would like to change.
git checkout -b feat/my-feature.Have a feature request? Open an issue.
dev.cluna — dev.cluna@gmail.com
Share your work with the community and get it listed in the Strapi ecosystem for everyone to discover and use.
Submit
