Form Editor

The Form Editor lets admins build custom forms for collecting data. It uses a three-panel layout: field types on the left (draggable), a live form preview in the center, and field settings on the right. This is a composite pattern. Not a single component. It combines MUI Tabs, List, TextField, Switch, and Card components wired together. It opens as a modal from inside the Workflow Editor when configuring a Form node.


Overview

The Form Editor lets admins build custom forms (registration, surveys, data collection) by selecting field types, configuring labels and validation, and previewing the result. No code.

When to use

Admin needs to create or edit a structured form within a workflow

Key interaction

Select field types, configure settings, reorder, preview, and save

Entry point

Workflow Editor → Form node → Configure

Interactive Preview

Form Fields
    Text Input
    Email
    Phone
    Number
    Date
    Textarea
    Select
    Radio
    Checkbox

Student Registration

Click a field to edit it, or add new fields from the left.

Field Settings
Field TypeText Input
Field Label
Required

Field Components

Each field type in the Form Editor maps to a specific MUI component (or combination of components). Use these references when building new field types or implementing form validation. All fields use the outlined variant for consistency.

Text Input

TextField

Single-line text entry for names, titles, or short answers.

Validation:maxLength, minLength, pattern (regex)
<TextField
  label="Full Name"
  variant="outlined"
  fullWidth
  required
  inputProps={{ maxLength: 100 }}
/>

Email

TextField

Email input with built-in browser validation.

Validation:type='email' auto-validates format
<TextField
  label="Email Address"
  type="email"
  variant="outlined"
  fullWidth
  required
/>

Phone

TextField

Phone number input with tel keyboard on mobile.

Validation:pattern for format, tel input type
<TextField
  label="Phone Number"
  type="tel"
  variant="outlined"
  fullWidth
  inputProps={{ pattern: "[0-9]*" }}
/>

Number

TextField

Numeric input with optional min/max/step constraints.

Validation:min, max, step attributes
<TextField
  label="Age"
  type="number"
  variant="outlined"
  fullWidth
  inputProps={{ min: 0, max: 120 }}
/>

Date

TextField + DatePicker

Date picker with calendar popup. Use MUI DatePicker in production.

Validation:min/max date bounds
import { DatePicker } from '@mui/x-date-pickers/DatePicker';

<DatePicker
  label="Date of Birth"
  slotProps={{ textField: { variant: 'outlined', fullWidth: true } }}
/>

Textarea

TextField (multiline)

Multi-line text entry for descriptions, comments, or long-form content.

Validation:maxLength for character limits
<TextField
  label="Description"
  variant="outlined"
  fullWidth
  multiline
  minRows={3}
  maxRows={8}
/>

Select

FormControl + Select + MenuItem

Dropdown for selecting one option from a list.

Validation:required prop on FormControl
<FormControl fullWidth>
  <InputLabel>Cohort</InputLabel>
  <Select label="Cohort" value={value} onChange={handleChange}>
    <MenuItem value="fall-2025">Fall 2025</MenuItem>
    <MenuItem value="spring-2026">Spring 2026</MenuItem>
  </Select>
</FormControl>

Radio

RadioGroup + FormControlLabel + Radio

Single selection from a small visible set of options (2–5).

Validation:required on FormControl wrapper
<FormControl>
  <FormLabel>Experience Level</FormLabel>
  <RadioGroup value={value} onChange={handleChange}>
    <FormControlLabel value="beginner" control={<Radio />} label="Beginner" />
    <FormControlLabel value="intermediate" control={<Radio />} label="Intermediate" />
    <FormControlLabel value="advanced" control={<Radio />} label="Advanced" />
  </RadioGroup>
</FormControl>

Checkbox

FormGroup + FormControlLabel + Checkbox

Multiple selections from a list, or single yes/no agreement.

Validation:required for single checkbox
<FormControl>
  <FormLabel>Interests</FormLabel>
  <FormGroup>
    <FormControlLabel
      control={<Checkbox checked={values.web} onChange={handleChange} name="web" />}
      label="Web Development"
    />
    <FormControlLabel
      control={<Checkbox checked={values.data} onChange={handleChange} name="data" />}
      label="Data Science"
    />
  </FormGroup>
</FormControl>

Form Field States

Default

Text Field

Selected

Text Field

Segmented Tabs

Property
Value

Track background

#F0F0F1gray100

Track radius

8pxradiusMd

Track padding

3px

Active tab bg

#FFFFFFsurfaceLight

Active tab shadow

0 1px 2px rgba(0,0,0,0.08)

Tab height

30px

Tab font

14px
·500

Active text

#141414gray900

Inactive text

#6B6B72gray500

Component Map

Each piece of the Form Editor maps to an existing atomic component or theme override.

Property
Value

Breadcrumb bar

Breadcrumbs + AppBar52px topbar

Segmented tabs

Tabs + TabBuilder / Preview toggle

Field types panel

List + ListItemButtonleft sidebar, 150px

Form canvas

BoxbgLight background, centered max-width

Field wrapper

Box1px border default, 2px primary when selected

Field input

TextFieldoutlined, inside wrapper

Settings panel

Boxright sidebar, 200px

Required toggle

Switchprimary color when on

Validation inputs

TextFieldtype=number, min/max length

Bottom actions

Buttonoutlined Cancel + contained Save

Interaction Flow

1

Entry

User opens Form Editor from a workflow node. Breadcrumb shows full path. Builder tab is active by default.

2

Adding fields

User drags or clicks a field type from the left panel. A new field wrapper appears on the canvas.

3

Selecting a field

Clicking a field wrapper highlights it with 2px orange border + primaryLight background. The right panel shows its settings.

4

Configuring

User edits label, placeholder, required toggle, and validation rules in the settings panel. Changes reflect live on the canvas.

5

Preview

User clicks the "Preview" tab to see the form as end users would see it, without builder chrome.

6

Saving

User clicks "Save". Form configuration is persisted. "Cancel" discards changes and returns to the workflow.

Code

Field wrapper, selected state
<Box
  sx={{
    border: isSelected ? '2px solid' : '1px solid',
    borderColor: isSelected ? 'primary.main' : 'grey.200',
    backgroundColor: isSelected ? 'primary.light' : 'white',
    borderRadius: '10px',
    p: 2,
    cursor: 'pointer',
  }}
  onClick={() => setSelectedField(field.id)}
>
  {children}
</Box>
Segmented tabs (Builder / Preview)
<Tabs value={activeTab} onChange={(_, v) => setActiveTab(v)}>
  <Tab label="Builder" />
  <Tab label="Preview" />
</Tabs>

// Theme overrides handle the segmented control styling:
// - gray100 track background
// - white active tab with subtle shadow
// - hidden indicator