Dynamic Form Builder

Complex signal graphs, real-time validation, computed form state, and JSON export

Field Palette

Form Fields 0 fields

Live Preview

How it works — View Source

// Complex signal graph for form builder
const fields = signal([], 'fields');
const formValues = signal({}, 'formValues');

// Each field's validity depends on its config + current value
const errors = computed(() => {
  return fields.value
    .filter(f => f.required)
    .flatMap(f => validate(f, formValues.value[f.id]));
});

const isValid = computed(() => errors.value.length === 0);

// Signal dependency graph:
//   fields ──┬──> errors ──> isValid
//            │
// formValues ┘
//
// Changing a field label re-validates.
// Typing in preview re-validates.
// Adding/removing fields re-validates.

// Validate based on field type
function validate(field, value) {
  const errs = [];
  if (field.required && !value)
    errs.push(`${field.label} is required`);
  if (field.type === 'email' && value && !value.includes('@'))
    errs.push(`${field.label} must be a valid email`);
  if (field.type === 'number' && value && isNaN(value))
    errs.push(`${field.label} must be a number`);
  return errs;
}