Building complex conditional forms + using LLM's for type analysis

Context

Our platform needed to publish a Defense Supplier Checklist as a marketplace offering. The challenge? Building a complex form with 26 interdependent questions, each requiring specific conditional logic based on previous answers. The kicker: it needed to be done under significant time pressure.

Note: While specific implementation details have been anonymized, this case study focuses on the technical approach to solving a common challenge in form builders: managing complex conditional logic while maintaining type safety and user experience.

What I Built

I developed an automated form generation system that could:

  1. Create hierarchical form structures with complex conditional logic
  2. Handle recursive dependencies between form fields
  3. Maintain type safety across the entire form structure
  4. Generate proper GraphQL mutations for form creation

The end result was a fully functional, conditional form workflow that guides users through a complex compliance checklist.

Technical Breakdown

Stack & Tools

Key Architecture Decisions

  1. Field ID Management System
interface FieldIds {
  [key: string]: {
    id: string;
    slug: string;
  };
}

// Store and track field IDs for conditions
const fieldIds: FieldIds = {};

// Create fields and store references
const choiceField = await createSingleChoiceField(
  tenantId,
  section.id,
  `q${questionNumber}`,
  label,
  conditions,
);

fieldIds[`q${questionNumber}`] = {
  id: choiceField.id,
  slug: choiceField.slug,
};

This system:

  1. Complex Conditional Logic
// Example of nested conditional logic
const conditions = {
  query: {
    expression: {
      condition: "AND",
      rules: Array.from({ length: 25 }, (_, idx) => ({
        id: fieldIds[`q${(idx + 1).toString().padStart(2, "0")}`].id,
        operator: "EQUALS_TO_OPTION",
        value: "1",
        slug: fieldIds[`q${(idx + 1).toString().padStart(2, "0")}`].slug,
      })),
    },
  },
};

// Field creation with conditions
await updateFormField(tenantId, field.id, {
  richTitle: label,
  metadata: {
    type: "SELECT",
    options: [
      { label: "Ja/Yes", value: "1" },
      { label: "Onderhanden/WIP", value: "2" },
      { label: "Nee/No", value: "0" },
    ],
    visible: conditions,
  },
});

The conditional system handles:

  1. LLM-Assisted Type Analysis
// Example of type structure fed to LLM
interface FormFieldMetadata {
  type: "SELECT" | "TEXTAREA" | "FILE_INPUT";
  visible?: {
    query: {
      expression: {
        condition: "AND" | "OR" | "NOT";
        rules: Array<{
          fieldId: string;
          operator: "EQUALS_TO_OPTION" | "NOT_EQUALS_TO_OPTION";
          value: string;
          slug: string;
        }>;
      };
    };
  };
  // ... other type definitions
}

Used LLM to:

What I Learned

  1. Time-Constrained Development

When faced with tight deadlines, I learned to:

  1. Type System Analysis

The approach of feeding type definitions to LLMs proved valuable:

  1. Conditional Form Architecture

Key insights about building conditional forms:

What's Next?

  1. Robustness Improvements

    • Build type validation system
    • Add condition testing framework
    • Implement condition visualization
    • Create condition templates
  2. Developer Experience

    • Build condition builder UI
    • Add type generation tools
    • Improve error messages
    • Create debugging tools
  3. Performance Optimization

    • Cache field references
    • Batch condition updates
    • Optimize condition evaluation
    • Implement change tracking

Key Takeaways

In this project what I took away is the importance of balancing technical debt with delivery speed. By leveraging LLMs for type analysis and focusing on core functionality, I was able to deliever a complex form build under tight time constraints (quicker than our CSM team could have done it manually).

Hey, sometimes the "perfect" solution isn't the right solution. In this case, using AI to understand and generate complex type structures was more efficient than building a comprehensive type system from scratch.

I think it demonstrated how modern development tools (like LLMs) can be creatively applied to solve traditional development challenges, especially when time is a critical factor.


Note: This case study focuses on the technical implementation while respecting confidentiality around specific requirements and implementations.