Form Definition Reference

Last modified: 4/23/2026

Form Definition Reference

This page describes the JSON schema that administrators write to define a form used by the Using FormPlugin.

Description

Each form is a JSON file stored on the server in the forms data directory. The file name (without .json) becomes the form's id used in the [{Form id='...'}] plugin invocation. Administrators create and edit these files directly; there is no browser-based form builder yet.

A form definition controls which fields appear, how they are validated, whether the submitter can enter data on behalf of someone else, and what happens after the form is submitted.

Top-Level Properties

PropertyTypeDefaultDescription
idstring*(required)*Lowercase alphanumeric with hyphens. Must match the filename (without .json).
titlestring*(required)*Display title shown at the top of the rendered form.
descriptionstring*(none)*Optional subtitle or instructions shown below the title.
handlerstring*(none)*Identifier of a registered server-side handler (e.g. "clubhouse-reservation"). If omitted, submissions are stored only.
proxySubmissionbooleanfalseWhen true, adds a collapsible **For Another Occupant** section so a staff member can submit on behalf of a resident.
notifyRolestring"admin"Role that receives in-app notifications for new submissions.
confirmationUrlstring*(none)*URL appended to the confirmation email sent to the submitter (e.g. "/view/makeareservation").
fieldsarray*(required)*Ordered list of field definitions. At least one field is required.

Field Properties

PropertyTypeDefaultDescription
namestring*(required)*Machine name used in the submitted data. Must be unique within the form.
typestring*(required)*Field type — see Field Types below.
labelstring*(required)*Human-readable label shown above the field.
requiredbooleanfalseWhen true, the field must be non-empty to submit.
descriptionstring*(none)*Optional helper text shown below the field.
placeholderstring*(none)*Placeholder text shown inside the input before the user types.
optionsarray of strings*(none)*Choices for dropdown fields when the list is defined inline.
optionsSourcestring*(none)*Dynamic option source — currently supports config:some.key to read a list from configuration.
prefillstring*(none)*Dot-path into the logged-in user's profile that pre-populates the field. See Prefill Paths below.

Field Types

TypeRenders asNotes
textSingle-line text inputGeneral purpose.
emailEmail inputValidated as a proper email address on submission.
telPhone number inputMust be at least 7 characters when required.
textareaMulti-line text area4 rows.
dateDate pickerBrowser native date input.
timeTime pickerBrowser native time input. If the form also has startTime and endTime fields, the server enforces that end time is after start time.
dropdownSelect menuRequires options or optionsSource.
checkboxCheckboxAccepted values on submission: on, true, or 1.
hiddenNot renderedContributes no data to the submission.
section<fieldset> group headerVisually groups the fields that follow it into a labelled fieldset. Contributes no data to the submission.

Section Field Type

A field with "type": "section" inserts a Bootstrap-styled <fieldset>/<legend> that groups all the fields listed after it (up to the next section or the end of the list). Only the name and label properties are used; all others are ignored.

Example — splitting a reservation form into two groups:

{ "name": "details", "type": "section", "label": "Reservation Details" },
{ "name": "date",    "type": "date",    "label": "Date", "required": true },
{ "name": "contact", "type": "section", "label": "Who Is the Reservation For?" },
{ "name": "name",    "type": "text",    "label": "Full Name", "required": true }

Fields before the first section marker are rendered without a fieldset wrapper.

Prefill Paths

When a logged-in user loads a page containing the form, any field with a prefill property is pre-populated with data from the user's profile. The value is always editable — prefill sets the default, not a locked value. Anonymous users see the field empty.

PathSource
user.displayNameUser's display name
user.firstNameUser's first name
user.lastNameUser's last name
user.emailUser's email address
user.cellPhoneUser's cell phone
user.homePhoneUser's home phone
user.unit.addressStreet address of the unit linked to the user's parcel number

The user.unit.* paths require the user's account to have a parcel value that matches an entry in the units data file. If no match is found, or if the user has no parcel, the field renders empty.

Proxy Submission (For Another Occupant)

When "proxySubmission": true, the rendered form appends a For Another Occupant fieldset after the regular fields. This section is optional — if left blank, the form submits normally on behalf of the logged-in user.

If any field in the proxy section is filled in, the Full Name field in that section becomes required. The server validates this and returns an error if name is missing while other proxy fields are filled.

Example Form Definition

{
  "id": "clubhouse-reservation",
  "title": "Clubhouse Reservation Request",
  "description": "Reserve the clubhouse for a private event. Subject to availability and board approval.",
  "handler": "clubhouse-reservation",
  "confirmationUrl": "/view/makeareservation",
  "proxySubmission": true,
  "notifyRole": "clubhouse-manager",
  "fields": [
    { "name": "details-section", "type": "section", "label": "Reservation Details" },
    { "name": "date",      "type": "date",     "label": "Date",        "required": true },
    { "name": "startTime", "type": "time",     "label": "Start Time",  "required": true },
    { "name": "endTime",   "type": "time",     "label": "End Time",    "required": true },
    { "name": "description", "type": "textarea", "label": "Event Description" },
    { "name": "address",   "type": "text",     "label": "Unit Address", "prefill": "user.unit.address" },
    { "name": "who-section", "type": "section", "label": "Who Is the Reservation For?" },
    { "name": "name",      "type": "text",     "label": "Full Name",   "required": true, "prefill": "user.displayName" },
    { "name": "email",     "type": "email",    "label": "Email",                         "prefill": "user.email" },
    { "name": "phone",     "type": "tel",      "label": "Phone",                         "prefill": "user.cellPhone" }
  ]
}

Notes