Form Component

Create dynamic forms with various field types and validation

Form Component

Overview

The Form component allows you to create dynamic forms with various field types, validation, and submission handling. It supports multiple input widgets and layouts for collecting user data.

Usage

To use the Form component in your tool handler, follow these steps:

  1. Import the FormUIBuilder and DainResponse from the @dainprotocol/utils package:
import { FormUIBuilder, DainResponse } from "@dainprotocol/utils";
  1. Create a FormUIBuilder instance and configure it:
const formUI = new FormUIBuilder()
  .title("Contact Form")              // Optional
  .description("Send us a message")   // Optional
  .addFields([                        // Mandatory
    {
      name: "name",
      label: "Full Name",
      type: "string",
      widget: "text",
      required: true
    },
    {
      name: "email",
      label: "Email Address",
      type: "string",
      widget: "email",
      required: true
    }
  ])
  .onSubmit({                        // Mandatory
    tool: "contactHandler",
    params: {
      source: "contact_form"
    }
  })
  .build();
  1. Return the FormUIBuilder instance in a DainResponse object:
return new DainResponse({
  text: "Contact form generated",
  data: { /* Your data */ },
  ui: formUI
});

Configuration

Mandatory Props

  • fields (FormField[]): Array of form field definitions
  • onSubmit: Action configuration for form submission

Optional Props

  • title (string): Form title
  • description (string): Form description
  • layout (string): Layout style identifier

Field Types and Widgets

Available field types:

  • string
  • number
  • boolean

Available widgets:

type FormFieldWidget =
    // Text inputs
    | "text" | "password" | "email" | "url" | "tel" | "search"
    // Date and time
    | "date" | "time" | "week" | "month" | "datetime-local"
    // Special inputs
    | "color" | "range" | "file" | "image"
    // Multi-line and selections
    | "textarea" | "select" | "radio" | "checkbox"
    // Other
    | "hidden" | "button" | "reset" | "submit"

FormField Interface

Each form field is defined using this interface:

interface FormField {
    name: string;        // Mandatory: field identifier
    type: FormFieldType; // Mandatory: data type
    label?: string;      // Optional: field label
    widget?: FormFieldWidget; // Optional: input widget type
    placeholder?: string;     // Optional: placeholder text
    required?: boolean;       // Optional: field requirement
    options?: Array<{        // Optional: for select/radio
        label: string;
        value: string | number;
    }>;
    defaultValue?: string | number | boolean; // Optional: default value
}

Actions

The Form component requires an onSubmit action that defines what happens when the form is submitted:

formUI.onSubmit({
  tool: "yourToolName",
  params: {
    // Predefined parameters
    source: "registration"
  }
});

Action Arguments

  • tool (string): The name of the tool to be called when the form is submitted. This is mandatory.

  • params (object): Pre-defined parameters that will be included with the form submission:

    • These values are set at build time and cannot be changed by the user
    • Useful for including constant values or context that should always be included
    • Optional, but recommended for tracking form sources or types
  • paramSchema: This is automatically generated from your form fields, so you don't need to specify it. The builder will:

    • Create a schema entry for each form field
    • Include validation rules based on field properties
    • Handle type conversion based on field types

For example, this form:

const form = new FormUIBuilder()
  .addFields([
    {
      name: "email",
      type: "string",
      required: true
    }
  ])
  .onSubmit({
    tool: "emailSubscribe",
    params: {
      list: "newsletter"
    }
  })
  .build();

Will automatically generate this paramSchema:

{
  email: { 
    type: "string",
    required: true
  }
}

Examples

Basic Contact Form

const contactForm = new FormUIBuilder()
  .title("Contact Us")
  .addFields([
    {
      name: "name",
      label: "Name",
      type: "string",
      widget: "text",
      required: true
    },
    {
      name: "message",
      label: "Message",
      type: "string",
      widget: "textarea",
      required: true
    }
  ])
  .onSubmit({
    tool: "messageHandler",
    params: {
      department: "support"
    }
  })
  .build();

return new DainResponse({
  text: "Contact Form",
  data: {},
  ui: contactForm
});

Registration Form with Multiple Widgets

const registrationForm = new FormUIBuilder()
  .title("Create Account")
  .description("Sign up for a new account")
  .addFields([
    {
      name: "email",
      label: "Email",
      type: "string",
      widget: "email",
      required: true
    },
    {
      name: "password",
      label: "Password",
      type: "string",
      widget: "password",
      required: true
    },
    {
      name: "role",
      label: "Account Type",
      type: "string",
      widget: "select",
      options: [
        { label: "Developer", value: "dev" },
        { label: "Designer", value: "design" }
      ],
      required: true
    },
    {
      name: "newsletter",
      label: "Subscribe to newsletter",
      type: "boolean",
      widget: "checkbox",
      defaultValue: true
    }
  ])
  .onSubmit({
    tool: "userRegistration",
    params: {
      source: "web"
    }
  })
  .build();

Booking Form with Date/Time

const bookingForm = new FormUIBuilder()
  .title("Schedule Appointment")
  .addFields([
    {
      name: "date",
      label: "Preferred Date",
      type: "string",
      widget: "date",
      required: true
    },
    {
      name: "time",
      label: "Preferred Time",
      type: "string",
      widget: "time",
      required: true
    },
    {
      name: "notes",
      label: "Special Requirements",
      type: "string",
      widget: "textarea"
    }
  ])
  .onSubmit({
    tool: "bookingHandler",
    params: {
      type: "appointment"
    },
    paramSchema: {
      date: {
        type: "string",
        required: true
      }
    }
  })
  .build();