Form Fields & Widgets

Customize create and edit forms with the admin's nine widgets: TextInput, TextareaInput, NumberInput, CheckboxInput, SelectInput, DateTimePicker, PasswordInput, RelationSelect and MultiRelationSelect. An unknown widget name falls back to TextInput (with a console warning).

Form Fields & Widgets

Customize create and edit forms with the admin's nine widgets: TextInput, TextareaInput, NumberInput, CheckboxInput, SelectInput, DateTimePicker, PasswordInput, RelationSelect and MultiRelationSelect. An unknown widget name falls back to TextInput (with a console warning).

Form fields are configured in nuxt.config, which is serialized to JSON on its way to the app: values must be data. A function (such as a condition) or a RegExp set there is lost.

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 is the API's (see Validation); a refused save shows the API's error message.

Available Widgets

TextInput

Basic single-line text input:

{
  name: 'title',
  widget: 'TextInput',
  placeholder: 'Enter title',
}

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, // default 4
  },
}

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 (default false)
  },
}

For date only:

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

PasswordInput

Password input with masked characters:

{
  name: 'password',
  widget: 'PasswordInput',
  required: true,
}

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: ['email'],   // Field to search by (optional; only the first entry is used, default displayField)
  },
}

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.

Widget Auto-Detection

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

ColumnAuto Widget
Foreign keyRelationSelect
Enum columnSelectInput
Name contains passwordPasswordInput
boolean, or integer named is…CheckboxInput
integer / numericNumberInput
Timestamp / date, or a name ending in At / DateDateTimePicker
text column, or a name containing description, content, body, bio, notesTextareaInput
Anything else (including JSON columns)TextInput

The first matching row wins. Generated forms leave out the primary key, createdAt, updatedAt and deletedAt.

Field Validation

required: true marks the field and blocks an empty submit ("This field is required" under the field). Every other rule comes from the API: the resource's validation schemas run on submit, and a refused save shows the API's error message (it is not mapped onto individual fields).

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: 'TextInput', required: true },

    // Content
    { name: 'excerpt', widget: 'TextareaInput' },
    { name: 'content', widget: 'TextareaInput', options: { rows: 12 } },

    // 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',
        },
        {
          name: 'slug',
          label: 'URL Slug',
          widget: 'TextInput',
          required: true,
        },
        {
          name: 'excerpt',
          label: 'Excerpt',
          widget: 'TextareaInput',
          placeholder: 'Brief summary...',
          options: {
            rows: 3,
          },
        },
        {
          name: 'content',
          label: 'Content',
          widget: 'TextareaInput',
          required: true,
          options: {
            rows: 12,
          },
        },
        {
          name: 'authorId',
          label: 'Author',
          widget: 'RelationSelect',
          required: true,
          options: {
            resource: 'users',
            displayField: 'name',
          },
        },
        {
          name: 'status',
          label: 'Status',
          widget: 'SelectInput',
          options: {
            enumValues: ['draft', 'published', 'archived'],
          },
        },
        {
          name: 'publishedAt',
          label: 'Publish Date',
          widget: 'DateTimePicker',
          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.