Skip to content
form-building logo

Form Building Skill

form-building

Building create/edit forms with FormField components, validation integration, and save patterns

SKILL.md

Full skill instructions

Form Building Skill

Core Principles

  • MobX state management - NO state hooks or other libraries unless specified
  • Group related fields using DetailFieldContainer
  • Ask first if unclear about field importance
  • Forms are for CREATE and EDIT operations

Available Components

Located in: ui/​src/​common/​components/​form/​fields/

Basic Fields

  • FormFieldText - Short text fields
  • FormFieldTextArea - Long text fields
  • FormFieldCheckbox - Boolean 0/​1 fields
  • FormFieldReadOnly - Display-only fields
  • FormFieldDate - Date picker
  • FormFieldColor - Color picker
  • FormFieldCodeEdit - Code editor

Single Select (Constants)

import { constants } from "@/​models/​constants";

<FormFieldSelect
  record={props.asset}
  field="status"
  label="Status"
  options={constants.asset.status}
/>

Multi Select (Constants)

<FormFieldMultiSelect
  record={props.account}
  field="permissions"
  label="Permissions"
  options={constants.account.permissions}
/>

Model Relationships

Small lists (< 50 options):

<FormFieldModelSelect<AssetModel, OrganizationModel>
  record={props.asset}
  field="organization_id"
  label="Organization"
  placeholder="Select Organization"
  modelName="organization"
  modelSearchField="q"
  modelDisplayField="label"
  modelSearchFilters={{ disabled: "0" }}
/>

Large lists (use search):

<FormFieldModelSearchSelect<AssetModel, OrganizationModel>
  record={props.asset}
  field="organization_id"
  label="Organization"
  placeholder="Search Organization"
  modelName="organization"
  modelSearchField="q"
  modelDisplayField="label"
  modelSearchFilters={{ disabled: "0" }}
/>

Multi-select (small lists):

<FormFieldModelMultiSelect<AssetModel, TagModel>
  record={props.asset}
  field="tag_ids"
  label="Tags"
  placeholder="Select Tags"
  modelName="tag"
  modelSearchField="q"
  modelDisplayField="label"
/>

Multi-select (large lists with search):

<FormFieldModelSearchMultiSelect<AssetModel, TagModel>
  record={props.asset}
  field="tag_ids"
  label="Tags"
  placeholder="Search Tags"
  modelName="tag"
  modelSearchField="q"
  modelDisplayField="label"
/>

Model Relationship Best Practices

  • Always try to use label as modelDisplayField
  • Always try to use q as modelSearchField
  • If model doesn't have a good label, modify it in XXModel.ts
  • Assume all models exist - don't create new ones

JSONB Fields Pattern

For nested JSONB objects:

// JSONB class must extend ValidationClass
<FormFieldTextArea
  record={props.organization.properties}
  field="pricing_text"
  label="Pricing Text"
  placeholder="Enter pricing text..."
  helpText="Default text if no pricing info in plan"
/>

Note: Unlike DetailFields, FormFields don't need parentRecord or SafeBaseModel wrapper

Grouping Fields with Container

<DetailFieldContainer label="Basic Information">
  <FormFieldText
    record={props.asset}
    field="name"
    label="Name"
    placeholder="Asset Name"
  />
  <FormFieldTextArea
    record={props.asset}
    field="description"
    label="Description"
    placeholder="Description..."
  />
</​DetailFieldContainer>

<DetailFieldContainer label="Organization Details">
  <FormFieldModelSearchSelect<AssetModel, OrganizationModel>
    record={props.asset}
    field="organization_id"
    label="Organization"
    modelName="organization"
    modelSearchField="q"
    modelDisplayField="label"
  />
  <FormFieldSelect
    record={props.asset}
    field="status"
    label="Status"
    options={constants.asset.status}
  />
</​DetailFieldContainer>

Complete Form Example

import { observer } from "mobx-react-lite";
import { AssetModel } from "@/​models/​asset";
import { OrganizationModel } from "@/​models/​organization";
import { constants } from "@/​models/​constants";
import {
  DetailFieldContainer,
  FormFieldText,
  FormFieldTextArea,
  FormFieldSelect,
  FormFieldModelSearchSelect,
  FormFieldCheckbox,
  FormFieldDate,
} from "@/​ui/​common/​components/​form/​fields";
import { Button } from "@/​ui/​shadcn/​ui/​button";

interface AssetFormProps {
  asset: AssetModel;
  onSave: () => void;
  onCancel: () => void;
}

export const AssetForm = observer((props: AssetFormProps) => {
  const handleSave = async () => {
    await props.asset.save();
    props.onSave();
  };

  return (
    <div className="space-y-6">
      <DetailFieldContainer label="Basic Information">
        <FormFieldText
          record={props.asset}
          field="name"
          label="Name"
          placeholder="Asset Name"
        />
        <FormFieldTextArea
          record={props.asset}
          field="description"
          label="Description"
          placeholder="Asset description..."
        />
        <FormFieldCheckbox
          record={props.asset}
          field="is_active"
          label="Is Active"
        />
      </​DetailFieldContainer>

      <DetailFieldContainer label="Organization & Status">
        <FormFieldModelSearchSelect<AssetModel, OrganizationModel>
          record={props.asset}
          field="organization_id"
          label="Organization"
          modelName="organization"
          modelSearchField="q"
          modelDisplayField="label"
          modelSearchFilters={{ disabled: "0" }}
        />
        <FormFieldSelect
          record={props.asset}
          field="status"
          label="Status"
          options={constants.asset.status}
        />
        <FormFieldDate
          record={props.asset}
          field="effective_date"
          label="Effective Date"
        />
      </​DetailFieldContainer>

      <div className="flex justify-end gap-2">
        <Button variant="outline" onClick={props.onCancel}>
          Cancel
        </​Button>
        <Button onClick={handleSave}>
          Save
        </​Button>
      </​div>
    </​div>
  );
});

Validation Integration

Forms automatically connect to model validation rules:

// Model already has validation rules defined
get validationRules() {
  return assetValidationRules;
}

// Form fields automatically show errors
<FormFieldText
  record={props.asset}
  field="name"
  label="Name"
  // Validation errors show automatically
/>

Save Pattern

const handleSave = async () => {
  try {
    await props.asset.save();
    // Success - redirect or close modal
    props.onSave();
  } catch (error) {
    // Error handling - validation errors show on fields automatically
    console.error("Save failed:", error);
  }
};

Key Differences from Details View

FeatureForm FieldsDetail Fields
Use caseCreate/​EditView/​Edit
JSONBDirect recordNeeds parentRecord
Type castingNot neededSafeBaseModel<T>
Save buttonRequiredOptional
ValidationBuilt-inBuilt-in

Key Rules

  1. Always create components with #ui_code_tools
  2. Use search variants for large option lists (>50 items)
  3. Constants are model-specific: constants.{model}.{field}
  4. Forms handle validation automatically via model rules
  5. Call model.save() to persist changes
  6. Ask before implementing if field importance is unclear
  7. JSONB fields don't need parentRecord in forms

More skills from majiayu000

xiaohongshu logo
majiayu000/claude-arsenal

xiaohongshu

xiaohongshu

286 148
View
agent-task-conductor logo
majiayu000/claude-skill-registry

agent-task-conductor

Conduct multi-agent task orchestration and workflow coordination.

663 1
View
conductor-setup logo
majiayu000/claude-skill-registry

conductor-setup

Initialize project with Conductor artifacts (product definition,

663 1
View
animation-designer logo
majiayu000/claude-skill-registry

animation-designer

Expert in web animations, transitions, and motion design using Framer Motion and CSS

663 1
View
diagramming logo
majiayu000/claude-skill-registry

diagramming

Creates Mermaid and ASCII diagrams for flowcharts, architecture, ERDs, state machines, mindmaps, and more. Use when user mentions diagram, flowchart, mermaid, ASCII diagram, text diagram, terminal diagram, visualize, C4, mindmap, architecture diagram, sequence diagram, ERD, or needs visual docume...

663 1
View
h3-pg logo
majiayu000/claude-skill-registry-data

h3-pg

PostgreSQL bindings for H3 hexagonal grid system. Use when working with H3 cells in Postgres, including spatial indexing, geometry/geography integration, and raster analysis.

23 1
View
conductor-development logo
majiayu000/claude-skill-registry

conductor-development

Context-Driven Development skill for projects using Conductor. Use this skill when you detect a `conductor/` directory in the project, when working on tasks defined in a `plan.md` file, or when the user asks about tracks, specs, or plans. Automatically applies TDD workflow, tracks task completion...

663 1
View
conductor-status logo
majiayu000/claude-skill-registry

conductor-status

Display project status, active tracks, and next actions

663 1
View
dockerization logo
majiayu000/claude-skill-registry

dockerization

Official Stakpak application containerization standard operating procedure, a step-by-step guidline to properly dockerize applications. This is a rule book curated by the Stakpak Team.

663 1
View

Popular AI tools

Kaiber logo
Video

Kaiber

Generate, edit, and beat-sync AI video with leading models in one workspace.

Paid
View
Vimcal logo
Productivity

Vimcal

The world's fastest calendar for remote work

Free
View

Transform Your Design with AI Designer by ImgCreator.ai

Freemium
View
Akool AI logo
Content & writing

Akool AI

Revolutionizing Video Production with AI-Powered Creativity

Paid
View

Extend an image past the frame and let AI fill the new aspect ratio.

Freemium
View
StarByFace logo
Security

StarByFace

Discover your celebrity doppelgänger with StarByFace!

Free
View
C

ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.

Freemium
View
Opus Clip logo
Coding & apps

Opus Clip

Opus.ai: Revolutionize Your Web Experience

Free
View