Form Fields & Widgets

Customize create and edit forms with various widget types.

Form Fields & Widgets

Customize create and edit forms with various widget types.

Field Configuration

Each form field is configured with:

{
  name: 'fieldName',           // Required: Schema column name
  label: 'Display Label',      // Optional: Shown above field
  widget: 'TextInput',         // Optional: Widget type (auto-detected if omitted)
  required: true,              // Optional: Validation
  readonly: false,             // Optional: Make field non-editable
  placeholder: 'Enter value',  // Optional: Placeholder text
  help: 'Helper text',         // Optional: Shown below field
  options: { /* ... */ },      // Optional: Widget-specific options
  validation: { /* ... */ },   // Optional: Custom validation
  condition: (formData) => true, // Optional: Conditional visibility
}

Available Widgets

TextInput

Basic single-line text input:

{
  name: 'title',
  widget: 'TextInput',
  placeholder: 'Enter title',
  options: {
    maxLength: 100,
    minLength: 3,
  },
}

NumberInput

Numeric input with optional constraints:

{
  name: 'price',
  widget: 'NumberInput',
  options: {
    min: 0,
    max: 10000,
    step: 0.01,  // For decimals
  },
}

TextareaInput

Multi-line text input:

{
  name: 'description',
  widget: 'TextareaInput',
  options: {
    rows: 5,
    maxLength: 500,
  },
}

CheckboxInput

Boolean checkbox:

{
  name: 'published',
  widget: 'CheckboxInput',
  label: 'Publish immediately',
}

SelectInput

Dropdown select with predefined options:

{
  name: 'status',
  widget: 'SelectInput',
  options: {
    enumValues: ['draft', 'published', 'archived'],
  },
}

Or with custom labels:

{
  name: 'role',
  widget: 'SelectInput',
  options: {
    options: [
      { label: 'Administrator', value: 'admin' },
      { label: 'Editor', value: 'editor' },
      { label: 'Viewer', value: 'viewer' },
    ],
  },
}

DateTimePicker

Date and/or time picker:

{
  name: 'publishedAt',
  widget: 'DateTimePicker',
  options: {
    showTime: true,      // Include time picker
    format: 'YYYY-MM-DD HH:mm',
  },
}

For date only:

{
  name: 'birthDate',
  widget: 'DateTimePicker',
  options: {
    showTime: false,
  },
}

PasswordInput

Password input with masked characters:

{
  name: 'password',
  widget: 'PasswordInput',
  required: true,
  options: {
    minLength: 8,
  },
}

RelationSelect

Select a related resource (foreign key):

{
  name: 'authorId',
  label: 'Author',
  widget: 'RelationSelect',
  options: {
    resource: 'users',         // Related resource name
    displayField: 'name',      // Field to show in dropdown
    searchFields: ['name', 'email'],  // Fields to search (optional)
  },
}

Features:

  • Async loading of related resources
  • Searchable dropdown with debouncing
  • Displays current selection even if not in search results

MultiRelationSelect

Select multiple related resources (M2M relationships):

{
  name: 'tags',
  label: 'Tags',
  widget: 'MultiRelationSelect',
  options: {
    resource: 'tags',
    displayField: 'name',
    junctionTable: 'postTags',
    junctionLeftKey: 'postId',
    junctionRightKey: 'tagId',
  },
}

Important: M2M fields should only be used in edit forms, not create forms. See M2M Relationships.

SlugInput

Auto-generate slugs from another field:

{
  name: 'slug',
  widget: 'SlugInput',
  options: {
    generateFrom: 'title',  // Auto-generate from title field
  },
}

RichTextEditor

WYSIWYG editor for rich content (requires additional setup):

{
  name: 'content',
  widget: 'RichTextEditor',
  options: {
    toolbar: ['bold', 'italic', 'link', 'heading'],
  },
}

MarkdownEditor

Markdown editor with preview:

{
  name: 'body',
  widget: 'MarkdownEditor',
}

CodeEditor

Syntax-highlighted code editor:

{
  name: 'config',
  widget: 'CodeEditor',
  options: {
    language: 'json',
    theme: 'vs-dark',
  },
}

JsonEditor

Specialized JSON editor with validation:

{
  name: 'metadata',
  widget: 'JsonEditor',
}

ColorPicker

Color selection:

{
  name: 'brandColor',
  widget: 'ColorPicker',
}

TagsInput

Multiple tags input:

{
  name: 'keywords',
  widget: 'TagsInput',
}

FileUpload

File upload (single file):

{
  name: 'document',
  widget: 'FileUpload',
  options: {
    accept: '.pdf,.doc,.docx',
    maxSize: 5242880,  // 5MB in bytes
  },
}

ImageUpload

Image upload with preview:

{
  name: 'avatar',
  widget: 'ImageUpload',
  options: {
    accept: 'image/*',
    maxSize: 2097152,  // 2MB
  },
}

Widget Auto-Detection

If you don't specify a widget, it's auto-detected from the schema:

Column TypeAuto Widget
integerNumberInput
textTextInput
booleanCheckboxInput
Enum columnSelectInput
Foreign keyRelationSelect
Date/TimestampDateTimePicker

Field Validation

Required Fields

{
  name: 'email',
  widget: 'TextInput',
  required: true,
}

Custom Validation

{
  name: 'email',
  widget: 'TextInput',
  validation: {
    pattern: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
    message: 'Please enter a valid email',
  },
}

Conditional Fields

Show/hide fields based on other field values:

{
  name: 'customDomain',
  widget: 'TextInput',
  condition: (formData) => formData.plan === 'enterprise',
}

The field only appears when the condition returns true.

Field Layout

Fields are displayed vertically in the order specified. For complex layouts, you can group related fields:

formFields: {
  create: [
    // Basic Info
    { name: 'title', widget: 'TextInput', required: true },
    { name: 'slug', widget: 'SlugInput', required: true },

    // Content
    { name: 'excerpt', widget: 'TextareaInput' },
    { name: 'content', widget: 'RichTextEditor' },

    // Publishing
    { name: 'status', widget: 'SelectInput' },
    { name: 'publishedAt', widget: 'DateTimePicker' },
    { name: 'authorId', widget: 'RelationSelect' },
  ],
}

Complete Example

resources: {
  posts: {
    formFields: {
      create: [
        {
          name: 'title',
          label: 'Post Title',
          widget: 'TextInput',
          required: true,
          placeholder: 'Enter a catchy title',
          help: 'This will be displayed as the main heading',
          options: {
            maxLength: 100,
          },
        },
        {
          name: 'slug',
          label: 'URL Slug',
          widget: 'SlugInput',
          required: true,
          options: {
            generateFrom: 'title',
          },
        },
        {
          name: 'excerpt',
          label: 'Excerpt',
          widget: 'TextareaInput',
          placeholder: 'Brief summary...',
          options: {
            rows: 3,
            maxLength: 200,
          },
        },
        {
          name: 'content',
          label: 'Content',
          widget: 'RichTextEditor',
          required: true,
        },
        {
          name: 'featuredImage',
          label: 'Featured Image',
          widget: 'ImageUpload',
          options: {
            accept: 'image/*',
            maxSize: 2097152,
          },
        },
        {
          name: 'authorId',
          label: 'Author',
          widget: 'RelationSelect',
          required: true,
          options: {
            resource: 'users',
            displayField: 'name',
            searchFields: ['name', 'email'],
          },
        },
        {
          name: 'status',
          label: 'Status',
          widget: 'SelectInput',
          options: {
            enumValues: ['draft', 'published', 'archived'],
          },
        },
        {
          name: 'publishedAt',
          label: 'Publish Date',
          widget: 'DateTimePicker',
          condition: (formData) => formData.status === 'published',
          options: {
            showTime: true,
          },
        },
        {
          name: 'featured',
          label: 'Featured Post',
          widget: 'CheckboxInput',
        },
      ],
      edit: [
        // Same as create, plus M2M relations
        // ... all create fields ...
        {
          name: 'tags',
          label: 'Tags',
          widget: 'MultiRelationSelect',
          options: {
            resource: 'tags',
            displayField: 'name',
            junctionTable: 'postTags',
            junctionLeftKey: 'postId',
            junctionRightKey: 'tagId',
          },
        },
      ],
    },
  },
}

Next Steps

Need a Landing Page?

Modern landing pages with optional modules (blog, docs, forms, i18n). Let's discuss your project.

Build Your MVP

Full-stack SaaS development. Expert in database design, multi-tenancy, and scalable architecture.

Deployment Help

Dockerize your backend, set up CI/CD pipelines, deploy to Cloudflare or Hetzner. Early-stage setup.

Suggest a SaaS Tool

Missing a calculator or tool? Suggest what you'd like to see on our site.