Skip to content

Formhaus vs SurveyJS ​

SurveyJS and Formhaus both render forms from JSON. SurveyJS is a full survey platform with many question types, an expression language and a commercial drag-and-drop builder; Formhaus is a small engine for product forms and funnels that renders with your own React, Vue and Figma components. For surveys, scored quizzes, matrix questions or a visual builder for non-developers, SurveyJS is the better choice. For forms that must look like the rest of your app and stay small, Formhaus is the lighter fit.

Choose SurveyJS when ​

  • Non-developers build forms in a drag-and-drop editor. Survey Creator does this; it needs a commercial developer license (licensing).
  • You need logic beyond show and hide: expressions, calculated values, enableIf and requiredIf (conditional logic).
  • The app uses Angular or plain JavaScript as well as React or Vue (overview).
  • You want ready themes and adapters for Bootstrap, Material UI and shadcn/ui (theme adapters).
  • You also need result dashboards or PDF export. SurveyJS sells Dashboard and PDF Generator (licensing).

Choose Formhaus when ​

  • Forms should render with your own field components through a components map, with no theme layer in between.
  • Bundle size matters: the Formhaus engine and React renderer together are about 11 KB gzipped.
  • Steps branch to different steps through explicit routes, and you want an MCP server to simulate every path.
  • Design works in Figma from the same definition the app renders.

Feature comparison ​

FormhausSurveyJS Form Library
Definition formatJSON, checked by a JSON SchemaSurveyJS JSON; linter and self-hosted schema validator (JSON validation)
Multi-stepBuilt in: steps, per-step validation, progress (guide)Built in: pages (multi-page survey)
Branching routesroutes on a step pick the next step (guide)Page visibleIf and the skip trigger to a question (conditional logic)
Conditional fieldsshow / showAny with five operators (guide)visibleIf, enableIf, requiredIf expressions (conditional logic)
ValidationDeclarative rules, named validators, async step validation (guide)Built-in validators, expression validators, onServerValidateQuestions (data validation)
Custom componentscomponents map per field type (guide)Custom question types and third-party components (integration)
FigmaPlugin draws the definition (guide)Figma design kit of SurveyJS components (FAQ, kit)
AI toolingJSON Schema, MCP server that validates definitions and simulates paths, Claude Code pluginMCP server for docs search, agent skills, AI chat in Survey Creator (demo)
FrameworksReact 18+, Vue 3.3+, headless engineReact, Angular, Vue 3, plain JavaScript (overview)
Bundle size (gzipped)6.2 KB core + 4.8 KB React322.5 KB survey-core 3.2.0 (bundlephobia) + 46.2 KB survey-react-ui 3.2.0 (bundlephobia)
LicenseMIT, all packagesForm Library MIT; Survey Creator, Dashboard and PDF Generator commercial (licensing)

Sizes measured on 2026-10-09. See how Formhaus sizes are measured.

Migration ​

The same sign-up form: email, plan, and a company field only for the Team plan.

SurveyJS ​

json
{
  "title": "Sign up",
  "completeText": "Create account",
  "elements": [
    {
      "type": "text",
      "name": "email",
      "title": "Email",
      "inputType": "email",
      "isRequired": true,
      "requiredErrorText": "Enter your email",
      "validators": [{ "type": "email", "text": "Enter a valid email" }]
    },
    {
      "type": "dropdown",
      "name": "plan",
      "title": "Plan",
      "isRequired": true,
      "choices": [
        { "value": "solo", "text": "Solo" },
        { "value": "team", "text": "Team" }
      ]
    },
    {
      "type": "text",
      "name": "company",
      "title": "Company",
      "visibleIf": "{plan} = 'team'",
      "isRequired": true,
      "requiredErrorText": "Enter your company"
    }
  ]
}
tsx
import 'survey-core/survey-core.css';
import { useEffect, useMemo } from 'react';
import { Model } from 'survey-core';
import { Survey } from 'survey-react-ui';
import signup from './signup-survey.json';

export function Signup({ onDone }: { onDone: (values: Record<string, unknown>) => void }) {
  const survey = useMemo(() => new Model(signup), []);

  useEffect(() => {
    const handler = (sender: Model) => onDone(sender.data);
    survey.onComplete.add(handler);
    return () => survey.onComplete.remove(handler);
  }, [survey, onDone]);

  return <Survey model={survey} />;
}

Formhaus ​

json
{
  "id": "signup",
  "title": "Sign up",
  "submit": { "label": "Create account" },
  "fields": [
    {
      "key": "email",
      "type": "email",
      "label": "Email",
      "validation": {
        "required": "Enter your email",
        "pattern": "^\\S+@\\S+$",
        "patternMessage": "Enter a valid email"
      }
    },
    {
      "key": "plan",
      "type": "select",
      "label": "Plan",
      "options": [
        { "value": "solo", "label": "Solo" },
        { "value": "team", "label": "Team" }
      ],
      "validation": { "required": true }
    },
    {
      "key": "company",
      "type": "text",
      "label": "Company",
      "show": [{ "field": "plan", "eq": "team" }],
      "validation": { "required": "Enter your company" }
    }
  ]
}
tsx
import { FormRenderer } from '@formhaus/react';
import type { FormDefinition } from '@formhaus/core';
import signup from './signup.json';

const definition = signup as FormDefinition;

export function Signup({ onDone }: { onDone: (values: Record<string, unknown>) => void }) {
  return <FormRenderer definition={definition} onSubmit={onDone} />;
}

elements become fields, name becomes key, title becomes label, choices become options, and visibleIf expressions become show conditions. pages map to steps. Expressions, calculated values and matrix questions have no Formhaus equivalent; keep those forms on SurveyJS.