What you’ll learn
After this tutorial, you’ll understand every part of a FormEngine JSON schema. You’ll know whatkey, type, props, children, schema, validations, and events do, and why they matter. By the end, you’ll be able to read any FormEngine JSON form and explain how it works to someone else.
This is NOT a reference manual — it’s a walkthrough like a teacher explaining a sentence word by word.
The simplest possible form
Let’s start with the absolute minimum: a text input field.Understanding the form tree: type, key, and children
FormEngine forms are trees, not flat lists. The root is always a "Screen" component, which is the page itself. Everything else is inside its children array.
The root: type: "Screen"
type: "Screen"— This tells FormEngine “I’m defining a page”. Every form must start with Screen as the root.children— An array of child components. Think of it like: “Inside this screen, place these components.”
Child components: type and key
Inside children, each component needs two things:
key — The data identifier
The key is the name of the field in your form’s data output. When a user types in this field, FormEngine captures the value under this key.
formEngine.getData(), you get:
"key": "email"). The key should be a valid JavaScript variable name (alphanumeric + underscore).
type — The component to render
The type tells FormEngine which UI component to use. FormEngine supports three families of components:
| Component family | Naming convention | Example | Comes from |
|---|---|---|---|
| React Suite | Start with Rs | RsInput, RsDropdown, RsCheckbox | @react-form-builder/components-rsuite (free) |
| Material UI | Start with Mui | MuiTextField, MuiSelect, MuiCheckbox | @react-form-builder/components-material-ui (free) |
| Mantine | Start with Mt | MtTextInput, MtSelect, MtCheckbox, MtRating | @react-form-builder/components-mantine (free) |
@react-form-builder/components-rsuite, you can only use Rs* types. You can’t use RsInput with a Mantine view.
If FormEngine encounters a type it doesn’t recognize, you’ll see an error in the browser console: Unknown component: UnknownType.
Nesting: children inside components
Components can have children. For example, a RsCard (a card-like container) can wrap multiple fields:
RsInput (a text field) doesn’t have children — it’s a leaf node. But layout components like RsCard, RsContainer, and RsTab do.
Check the component documentation to see which components support children.
Component properties: the props object
The props object configures how a component looks and behaves. It maps to the component’s React props.
The { "value": ... } wrapper pattern
You might notice that every prop value is wrapped in { "value": ... }. This looks redundant, but it’s intentional:
{ "value": ... } with { "computed": "path.to.value" } or { "if": [...] }. The wrapper prepares your schema for these advanced patterns.
For now, just remember: every prop value goes inside { "value": ... }.
Common props for input components
Most input components (text, dropdown, checkbox) support these props:| Prop | Type | Example | What it does |
|---|---|---|---|
label | string | { "value": "Full Name" } | The label displayed above the field |
placeholder | string | { "value": "Enter your name" } | Placeholder text inside the field |
disabled | boolean | { "value": false } | If true, user can’t interact with the field |
size | string | { "value": "lg" } | Size: "sm", "md", "lg" (component-dependent) |
required | boolean | { "value": true } | If true, adds a red asterisk (*) to the label |
hidden | boolean | { "value": false } | If true, the field is hidden (but still in data) |
helpText | string | { "value": "We'll use this to contact you" } | Helper text displayed below the field |
RsInput might support maxLength, but RsDropdown doesn’t. Always check the component reference for the full list.
Adding validation: the schema object
Validation tells FormEngine which data is valid and which is not.
schema object contains validation rules in a validations array. Each rule has:
key— The rule name (e.g.,"required","email","minLength")args— Rule-specific arguments, usually including a custom error message
Available validation rules
| Rule | Usage | Error message |
|---|---|---|
required | Field must not be empty | (default) “This field is required” |
email | Field must be a valid email | (default) “Please enter a valid email” |
min | Number must be ≥ value | args: { "min": 18, "message": "Must be 18 or older" } |
max | Number must be ≤ value | args: { "max": 100, "message": "Max value is 100" } |
minLength | String must be ≥ N characters | args: { "minLength": 3, "message": "At least 3 characters" } |
maxLength | String must be ≤ N characters | args: { "maxLength": 50, "message": "Max 50 characters" } |
regex | String must match pattern | args: { "pattern": "^[A-Z]", "message": "Must start with capital letter" } |
match | Value must match another field | args: { "field": "password", "message": "Passwords don't match" } |
custom | Custom validation function | args: { "fn": "myCustomRule", "message": "Invalid input" } |
Custom error messages
By default, each rule has a built-in error message. But you can override it:Wiring interactivity: the events object
Events let fields respond to user actions. For example, when a user submits a form, clears a field, or selects a dropdown option.
Common event types
| Event | Triggered | Example use case |
|---|---|---|
onChange | User changes the field value | Clear dependent fields, calculate total price, update summary |
onClick | User clicks a button | Submit form, save draft, show modal |
onBlur | User leaves the field | Validate field, load suggestions |
onFocus | User enters the field | Show help text, load options |
Action reference format
Inside events, you reference actions by name:Top-level form settings
Beyond the tree structure, every FormEngine form has top-level configuration:tooltipType, errorType, modalType
These control how FormEngine displays validation messages and help text:
tooltipType: "icon"— Show a small (i) icon; clicking it displays help texterrorType: "inline"— Display error messages directly below the fieldmodalType: "center"— Center modals on screen (vs"full"for full-screen)
localization
If your form supports multiple languages, define them here. This is covered in the localization guide.
actions
Define custom actions that fields can trigger:
Complete annotated example: a contact form
Let’s put it all together. Here’s a real contact form with every part explained:Where to find available components and their props
Now that you understand the structure, you need to know which components exist and what props they support.- React Suite components — Browse all RSuite components
- Material UI components — Browse all MUI components
- Mantine components — Browse all Mantine components
- What the component looks like
- All available props with descriptions
- Code examples
Common mistakes
Mistake 1: Missing or duplicate key
Mistake 2: Wrong component type
Unknown component: RsInpu or Unknown component: RsInput.
How to fix: Check the component list for your package, and use the exact name shown.
Mistake 3: Forgetting the { "value": ... } wrapper
Mistake 4: Using the wrong validation rule name
Mistake 5: Putting non-leaf components in a field’s children
Troubleshooting: when things go wrong
”Unknown component: RsInput” error
Cause: Either the component name is misspelled, or you haven’t installed the correct UI library package. Fix:- Check the exact component name in the component reference
- Verify you installed the right package:
npm install @react-form-builder/components-rsuite - Import the components in your React code
Form doesn’t render, or renders empty
Cause: Could be several things:- Missing
"type": "Screen"at the root - Typo in a component’s
typeproperty - Syntax error in the JSON (extra comma, missing bracket)
- Open the browser’s Developer Console (F12 → Console tab)
- Look for red error messages — they usually tell you what’s wrong
- Copy the error message and search the docs, or ask in GitHub Issues
Field value doesn’t save (data is empty)
Cause: The field doesn’t have akey property.
Fix: Add "key": "fieldName" to every input field.
Validation doesn’t show errors
Cause:- The validation rule name is misspelled (use
"email", not"isEmail") errorTypeis set to"none"(so errors aren’t displayed)- The field doesn’t have a
schemaobject
- Check the validation rules list for correct rule names
- Set
"errorType": "inline"or"tooltip"at the form level - Make sure each field has a
schema.validationsarray
Button or dropdown doesn’t work
Cause: The component is missing anevents object with the correct action.
Fix: Add an events object to the button or dropdown, and reference the action you want to trigger.
Next steps
Now that you understand JSON structure, here’s where to go next:- Form Data Handling — How to get data from the form, set initial values, and reset fields
- Conditional Fields — Show/hide fields based on user input
- Zod Validation — Use the Zod schema library for powerful, type-safe validation
- Dynamic Dropdowns — Load dropdown options from an API
- Building Forms via Code — A guide for developers who prefer code over visual builders