Integration & API
Render forms in Razor views with the FormPicker property editor and view component, accept submissions from decoupled frontends via the headless API, and customize styling and labels per form.
FormPicker Property Editor
The FormForge.FormPickerproperty editor lets content editors select a form directly from the content node editing interface. The stored value is the form's GUID, which is automatically converted into a FormReference object (with Id, Alias, and Name properties) by the built-in value converter.
Adding to a Document Type
- Open the Umbraco backoffice and navigate to Settings → Document Types.
- Edit the Document Type where you want editors to select a form (e.g. your
Contact Pagedocument type). - Add a new property with any name (e.g.
Contact Form) and select FormForge.FormPicker as the property editor. - Save the Document Type. Content editors can now pick a form when editing nodes of that type.
Usage in Razor
Retrieve the selected form reference from the content model and pass it to the FormForgeRenderer view component:
@{
var formRef = Model.Value<FormReference>("contactForm");
if (formRef != null)
{
@await Component.InvokeAsync("FormForgeRenderer", new { formId = formRef.Id })
}
}The property alias passed to Model.Value<FormReference> must match the alias you configured on the Document Type property (in this example, contactForm).
You can also use formRef.Alias instead of formRef.Id when invoking the renderer. Alias-based lookups are recommended because they are more readable and environment-portable (aliases survive import/export across environments while GUIDs do not).
View Component
The FormForgeRenderer view component is the primary method for rendering a form on any Razor page or partial. It outputs a complete, self-contained form including all fields, multi-page navigation, client-side validation, CAPTCHA integration, and the configured success message.
Invocation
There are two ways to invoke the renderer:
// By form alias (recommended)
@await Component.InvokeAsync("FormForgeRenderer", new { formAlias = "contact-form" })
// By form ID
@await Component.InvokeAsync("FormForgeRenderer", new { formId = someGuid })Using the alias is recommended for readability and because aliases are stable across environments when using Import / Export.
Headless API
FormForge exposes a public JSON API for submitting forms from headless or decoupled frontends (React, Vue, mobile apps, etc.) where Razor rendering is not used. The endpoint is anonymous and rate-limited.
Endpoint
POST /api/v1/formforge/public/submit/{formAlias}Request
Send a JSON body with field alias/value pairs and an optional CAPTCHA token:
{
"fields": {
"name": "Jane Doe",
"email": "[email protected]",
"message": "Hello from a headless frontend!"
},
"captchaToken": "cf-turnstile-token-here"
}Response
The API returns a JSON object indicating success or failure:
// Success (200)
{
"success": true,
"submissionId": "a1b2c3d4-...",
"redirectUrl": "/thank-you"
}
// Validation error (400)
{
"success": false,
"errors": {
"email": "Please enter a valid email address.",
"name": "Name is required."
}
}The redirectUrl field is only present when a redirect URL is configured on the form. If no redirect is configured, handle the success state in your frontend (e.g. show a confirmation message).
JavaScript Example
async function submitForm(formAlias, data) {
const res = await fetch(`/api/v1/formforge/public/submit/${formAlias}`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ fields: data }),
});
const result = await res.json();
if (!result.success) {
// result.errors is an object keyed by field alias
console.error("Validation errors:", result.errors);
return;
}
if (result.redirectUrl) {
window.location.href = result.redirectUrl;
} else {
// Show your own success message
console.log("Submitted:", result.submissionId);
}
}The public submit endpoint is rate-limited and does not require authentication. If CAPTCHA is enabled on the form, include the captchaToken field in your request body or the submission will be rejected.
Theming
FormForge ships with a default stylesheet that provides clean, accessible form styling out of the box. The stylesheet is loaded automatically by the view component from /App_Plugins/FormForge/css/formforge.css— you do not need to reference it manually in your layout.
To match your site's design, override any of the default styles in your own stylesheet. All rendered elements use namespaced .formforge-* class names, so overrides are straightforward:
/* Example: custom form width and input styling */
.formforge-form {
max-width: 640px;
margin: 0 auto;
}
.formforge-field input,
.formforge-field textarea,
.formforge-field select {
border: 1px solid #d1d5db;
border-radius: 8px;
padding: 0.625rem 0.875rem;
}
.formforge-error {
color: #ef4444;
font-size: 0.8125rem;
}Localization
FormForge supports per-form localization, allowing you to customize all user-facing labels and messages independently for each form. This is configured in the form settings within the Umbraco backoffice, or via the management API.
Customizable Strings
| Setting | Default Value | Description |
|---|---|---|
SubmitButtonLabel | "Submit" | Text displayed on the form's submit button. |
Locale.NextLabel | "Next" | Text displayed on the Next button for multi-page form navigation. |
Locale.PreviousLabel | "Previous" | Text displayed on the Previous button for multi-page form navigation. |
DefaultRequiredMessage | "{label} is required." | Validation message for required fields. The {label}token is replaced with the field's label at render time (e.g. "Email is required."). |
SuccessMessage | "Thank you for your submission." | Message displayed after a successful form submission (unless a redirect URL is configured). |
Configuration Example
{
"settings": {
"submitButtonLabel": "Versturen",
"successMessage": "Bedankt voor uw bericht!",
"defaultRequiredMessage": "{label} is verplicht.",
"locale": {
"nextLabel": "Volgende",
"previousLabel": "Vorige"
}
}
}For sites with multiple languages, create a separate form per language with the appropriate locale settings. Use the FormPicker property editor on language-specific content nodes, or use conditional logic in your Razor templates to invoke the correct form alias based on the current culture.