S
Documentation

useSurvey Hook

The useSurvey hook is the heart of the library. It gives you full, headless control over survey state, navigation, validation, and submission — while you own the rendering.

Signature

function useSurvey(
  schema: SurveySchema,
  options?: SurveyOptions
): UseSurveyReturn;

Options

SurveyOptionstypescript
interface SurveyOptions {
  initialAnswers?: SurveyAnswers;
  onChange?: (answers: SurveyAnswers, questionId: string) => void;
  onSubmit?: (answers: SurveyAnswers) => void | Promise<void>;
  onValidate?: (errors: ValidationError[]) => void;
  onPageChange?: (pageIndex: number) => void;
  validators?: Record<string, (value: AnswerValue, question: Question, answers: SurveyAnswers) => string | null>;
}
initialAnswers

Pre-populate answers. Useful for edit mode or saved progress.

onChange

Called whenever an answer changes. Receives all answers and the changed question ID.

onSubmit

Called when the survey is submitted after validation passes. Can be async.

onValidate

Called when validation runs. Receives all validation errors.

onPageChange

Called when navigating to a different page.

validators

Custom validator functions keyed by question ID.

Return Object

UseSurveyReturntypescript
interface UseSurveyReturn {
  // Survey data
  survey: SurveySchema;           // Parsed schema
  answers: SurveyAnswers;          // Current answers

  // Answer management
  setAnswer: (id: string, value: AnswerValue) => void;
  setAnswers: (answers: SurveyAnswers) => void;

  // Validation
  errors: ValidationError[];       // Current errors
  getError: (id: string) => string | undefined;
  isValid: boolean;
  validate: () => boolean;
  validateCurrentPage: () => boolean;

  // Visibility
  getVisibleQuestions: () => Question[];
  getPageQuestions: (pageIndex: number) => Question[];
  visiblePages: Page[];

  // Navigation
  currentPageIndex: number;
  totalPages: number;
  hasNextPage: boolean;
  hasPrevPage: boolean;
  nextPage: () => boolean;
  prevPage: () => void;
  goToPage: (index: number) => boolean;

  // Submission
  submit: () => Promise<void>;
  isSubmitted: boolean;
  reset: () => void;

  // Progress
  progress: number;                // 0-100
}

Basic Usage

Basic Exampletsx
import { useSurvey } from 'react-minimal-survey-builder';

function MyForm() {
  const {
    answers, setAnswer,
    getVisibleQuestions, getError,
    nextPage, prevPage, submit,
    currentPageIndex, totalPages, progress,
  } = useSurvey(schema, {
    initialAnswers: { name: 'John' },
    onSubmit: async (answers) => {
      await saveToDatabase(answers);
    },
  });

  return (
    <form onSubmit={(e) => { e.preventDefault(); submit(); }}>
      {/* Progress */}
      <div className="progress" style={{ width: `${progress}%` }} />

      {/* Questions */}
      {getVisibleQuestions().map((q) => (
        <div key={q.id}>
          <label>{q.label}</label>
          <input
            value={(answers[q.id] as string) ?? ''}
            onChange={(e) => setAnswer(q.id, e.target.value)}
          />
          {getError(q.id) && <span className="error">{getError(q.id)}</span>}
        </div>
      ))}

      {/* Navigation */}
      <div>
        <span>Page {currentPageIndex + 1} of {totalPages}</span>
        {currentPageIndex > 0 && <button onClick={prevPage}>Back</button>}
        {currentPageIndex < totalPages - 1
          ? <button onClick={nextPage}>Next</button>
          : <button type="submit">Submit</button>}
      </div>
    </form>
  );
}

Performance

Stable callbacks

All returned functions use refs internally so they maintain stable identity across re-renders. Safe to use as dependencies.

Memoized schema

The schema is parsed once and memoized. Subsequent renders skip the parsing step.

Computed visibility

Condition evaluation and visibility are recalculated only when answers change.