Core Concepts

Fields & Schemas

NovaForms uses a JSON schema approach to define form fields. Each field is a JavaScript object that describes the input type, behavior, and appearance. This guide covers all available field types and their configuration options.


Field Schema Structure

Every field object has a basic structure:

{
  name: "fieldName",        // Required: Unique identifier
  type: "fieldType",        // Required: Field type
  title: "Display Label",   // Optional: Human-readable label
  width: 100,               // Optional: Width percentage (25, 50, 75, 100)
  default: "defaultValue",   // Optional: Default value
  // ... type-specific options
}

Core Field Properties

PropertyTypeRequiredDescription
namestringYesUnique field identifier
typestringYesField type (see types below)
titlestringNoDisplay label
labelstringNoLegacy display label (use title)
widthnumberNoWidth percentage (25, 50, 75, 100)
defaultanyNoDefault value
requiredbooleanNoMark field as required
readOnlybooleanNoMake field read-only
placeholderstringNoPlaceholder text
descriptionstringNoHelp text below field
helperstringNoAdditional help text
errorstringNoError message to display
leadingIconComponentNoIcon component before input
trailingIconComponentNoIcon component after input

Built-in Field Types

Text Input Fields

string - Text Input

Basic text input field.

Loading preview...
{
  name: "firstName",
  type: "string",
  title: "First Name",
  placeholder: "Enter your first name",
  required: true
}

text - Textarea

Multi-line text input.

Loading preview...
{
  name: "message",
  type: "text",
  title: "Message",
  placeholder: "Enter your message here...",
  width: 100
}

email - Email Input

Email input with built-in validation.

Loading preview...
{
  name: "email",
  type: "email",
  title: "Email Address",
  required: true,
  pattern: [
    {
      regex: "^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$",
      message: "Please enter a valid email address"
    }
  ]
}

tel - Phone Input

Phone number input.

Loading preview...
{
  name: "phone",
  type: "tel",
  title: "Phone Number",
  placeholder: "(555) 123-4567"
}

url - URL Input

URL input with validation.

{
  name: "website",
  type: "url",
  title: "Website",
  placeholder: "https://example.com"
}

Numeric Fields

number - Number Input

Numeric input field.

Loading preview...
{
  name: "age",
  type: "number",
  title: "Age",
  default: 0,
  min: 0,
  max: 120
}

Boolean Fields

boolean - Checkbox

Single checkbox field.

Loading preview...
{
  name: "subscribe",
  type: "boolean",
  title: "Subscribe to newsletter",
  default: false
}

toggle - Toggle Switch

Toggle switch component.

{
  name: "notifications",
  type: "toggle",
  title: "Enable notifications",
  default: true
}

Date & Time Fields

date - Date Picker

Date selection input.

{
  name: "birthDate",
  type: "date",
  title: "Birth Date",
  required: true
}

datetime - Date & Time Picker

Date and time selection input.

{
  name: "eventTime",
  type: "datetime",
  title: "Event Date & Time",
  required: true
}

time - Time Picker

Time selection input.

{
  name: "startTime",
  type: "time",
  title: "Start Time",
  default: "09:00"
}

Selection Fields

select - Single Select Dropdown

Single selection dropdown.

Loading preview...
{
  name: "country",
  type: "select",
  title: "Country",
  options: [
    { value: "us", label: "United States" },
    { value: "ca", label: "Canada" },
    { value: "mx", label: "Mexico" }
  ],
  required: true
}

multiselect - Multi-Select Dropdown

Multiple selection dropdown.

Loading preview...
{
  name: "interests",
  type: "multiselect",
  title: "Areas of Interest",
  options: [
    { value: "tech", label: "Technology" },
    { value: "design", label: "Design" },
    { value: "business", label: "Business" },
    { value: "marketing", label: "Marketing" }
  ]
}

radio - Radio Button Group

Radio button group for single selection.

Loading preview...
{
  name: "contactMethod",
  type: "radio",
  title: "Preferred Contact Method",
  options: [
    { value: "email", label: "Email" },
    { value: "phone", label: "Phone" },
    { value: "sms", label: "SMS" }
  ],
  required: true
}

File Upload Fields

file - Basic File Upload

Simple file upload input.

{
  name: "resume",
  type: "file",
  title: "Resume",
  accept: ".pdf,.doc,.docx"
}

fileV2 - Enhanced File Upload

Advanced file upload with preview.

{
  name: "profilePhoto",
  type: "fileV2",
  title: "Profile Photo",
  accept: "image/*"
}

uploadToBase - Base64 Image Upload

Image upload that converts to base64.

{
  name: "avatar",
  type: "uploadToBase",
  title: "Avatar",
  maxSize: 1024 * 1024  // 1MB
}

Specialized Fields

color - Color Picker

Color selection input.

Loading preview...
{
  name: "themeColor",
  type: "color",
  title: "Theme Color",
  default: "#3b82f6"
}

signature - Signature Pad

Digital signature input.

{
  name: "signature",
  type: "signature",
  title: "Digital Signature",
  required: true
}

rating - Star Rating

Star rating component.

Loading preview...
{
  name: "satisfaction",
  type: "rating",
  title: "Rate your experience",
  maxRating: 5,
  default: 0
}

scale - Likert Scale

Likert scale rating.

{
  name: "agreement",
  type: "scale",
  title: "I agree with the terms",
  min: 1,
  max: 5,
  labels: ["Strongly Disagree", "Disagree", "Neutral", "Agree", "Strongly Agree"]
}

captcha - reCAPTCHA

reCAPTCHA verification.

{
  name: "captcha",
  type: "captcha",
  siteKey: "your-recaptcha-site-key"
}

Layout Fields

header - Section Header

Section header for form organization.

{
  name: "personalInfoHeader",
  type: "header",
  title: "Personal Information",
  width: 100
}

paragraph - Static Text

Static text content.

{
  name: "instructions",
  type: "paragraph",
  content: "Please fill out all required fields marked with an asterisk (*).",
  width: 100
}

image - Static Image

Static image display.

{
  name: "logo",
  type: "image",
  image: {
    src: "/images/logo.png",
    alt: "Company Logo"
  },
  width: 100
}

Complex Fields

array - Dynamic Array/Subform

Dynamic array of objects with add/remove functionality.

Loading preview...
{
  name: "addresses",
  type: "array",
  title: "Addresses",
  width: 100,
  fields: [
    { name: "street", type: "string", title: "Street", width: 100 },
    { name: "city", type: "string", title: "City", width: 50 },
    { name: "state", type: "string", title: "State", width: 25 },
    { name: "zip", type: "string", title: "ZIP", width: 25 }
  ]
}

subForm - Nested Form Group

Nested form group (similar to array but for single objects).

{
  name: "emergencyContact",
  type: "subForm",
  title: "Emergency Contact",
  width: 100,
  fields: [
    { name: "name", type: "string", title: "Name", width: 100 },
    { name: "relationship", type: "string", title: "Relationship", width: 50 },
    { name: "phone", type: "tel", title: "Phone", width: 50 }
  ]
}

Field Options

Select Field Options

For select, multiselect, and radio fields:

{
  name: "category",
  type: "select",
  options: [
    { value: "option1", label: "Option 1" },
    { value: "option2", label: "Option 2" },
    { value: "option3", label: "Option 3" }
  ]
}

Pattern Validation

Client-side validation with regex patterns:

{
  name: "phone",
  type: "tel",
  pattern: [
    {
      regex: "^\\d{3}-\\d{3}-\\d{4}$",
      message: "Please enter phone number as XXX-XXX-XXXX"
    }
  ]
}

Multiple patterns:

{
  name: "email",
  type: "email",
  pattern: [
    {
      regex: "^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$",
      message: "Please enter a valid email address"
    },
    {
      regex: ".*@company\\.com$",
      message: "Please use your company email"
    }
  ]
}

Conditional Logic

Field Conditions

Control field visibility and state:

{
  name: "phone",
  type: "tel",
  title: "Phone Number",
  conditions: {
    hiddenWhen: [
      { field: "contactMethod", when: "equal", value: "email" }
    ],
    hiddenMode: "any"  // or "all"
  }
}

Read-Only Conditions

Make fields read-only based on conditions:

{
  name: "age",
  type: "number",
  title: "Age",
  conditions: {
    readOnlyWhen: [
      { field: "age", when: "less than", value: 0 },
      { field: "age", when: "greater than", value: 120 }
    ],
    readOnlyMode: "any"
  }
}

Triggers and Rules

Field Triggers

Trigger rules when field values change:

{
  name: "quantity",
  type: "number",
  triggers: [
    {
      rule: "calculateTotal",
      when: "not empty"
    }
  ]
}

Complex triggers:

{
  name: "discountCode",
  type: "string",
  triggers: [
    {
      rule: "applyDiscount",
      when: [
        { field: "discountCode", when: "matches", value: "SAVE10" },
        { field: "subtotal", when: "greater than", value: 50 }
      ],
      mode: "all"
    }
  ]
}

Layout and Styling

Width Classes

Fields automatically get responsive width classes:

  • width: 25w-full sm:w-1/4
  • width: 50w-full sm:w-1/2
  • width: 75w-full sm:w-3/4
  • width: 100w-full

Icon Support

Add icons to fields:

import { UserIcon, MailIcon } from "@heroicons/react/24/outline";

const fields = [
  {
    name: "username",
    type: "string",
    title: "Username",
    leadingIcon: UserIcon
  },
  {
    name: "email",
    type: "email",
    title: "Email",
    leadingIcon: MailIcon
  }
];

Best Practices

1. Use Descriptive Names

// ✅ Good
{ name: "userEmailAddress", type: "email", title: "Email Address" }

// ❌ Avoid
{ name: "email", type: "email", title: "Email" }

2. Provide Helpful Placeholders

// ✅ Good
{ name: "phone", type: "tel", placeholder: "(555) 123-4567" }

// ❌ Avoid
{ name: "phone", type: "tel", placeholder: "Phone" }

3. Use Appropriate Field Types

// ✅ Good
{ name: "age", type: "number", min: 0, max: 120 }

// ❌ Avoid
{ name: "age", type: "string", pattern: [{ regex: "^\\d+$" }] }
const fields = [
  // Personal Information
  { name: "firstName", type: "string", title: "First Name", width: 50 },
  { name: "lastName", type: "string", title: "Last Name", width: 50 },
  { name: "email", type: "email", title: "Email", width: 100 },
  
  // Contact Information
  { name: "phone", type: "tel", title: "Phone", width: 50 },
  { name: "address", type: "text", title: "Address", width: 100 }
];

5. Use Default Values Wisely

// ✅ Good: Sensible defaults
{ name: "country", type: "select", default: "us" }
{ name: "notifications", type: "boolean", default: true }

// ❌ Avoid: Confusing defaults
{ name: "firstName", type: "string", default: "John" }

Common Patterns

Form with Validation

Loading preview...
const fields = [
  {
    name: "email",
    type: "email",
    title: "Email Address",
    required: true,
    pattern: [
      {
        regex: "^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$",
        message: "Please enter a valid email address"
      }
    ]
  },
  {
    name: "password",
    type: "string",
    title: "Password",
    required: true,
    pattern: [
      {
        regex: "^.{8,}$",
        message: "Password must be at least 8 characters"
      }
    ]
  }
];

Conditional Fields

const fields = [
  {
    name: "hasAddress",
    type: "boolean",
    title: "Do you have a mailing address?"
  },
  {
    name: "street",
    type: "string",
    title: "Street Address",
    conditions: {
      hiddenWhen: [
        { field: "hasAddress", when: "equal", value: false }
      ]
    }
  }
];

Dynamic Arrays

const fields = [
  {
    name: "skills",
    type: "array",
    title: "Skills",
    fields: [
      { name: "name", type: "string", title: "Skill Name", width: 50 },
      { name: "level", type: "select", title: "Level", width: 50, options: [
        { value: "beginner", label: "Beginner" },
        { value: "intermediate", label: "Intermediate" },
        { value: "advanced", label: "Advanced" }
      ]}
    ]
  }
];

This comprehensive field reference covers all built-in field types and their configuration options. Use it as a reference when building your NovaForms schemas.

Previous
Quick Start