SSocratic UI

Question Sequence

Chain multiple Socratic components into a single flow. Asks one question at a time with pagination, skip/next actions, keyboard navigation, and edit-mode back-nav that restores prior answers.

Preview

What's your vibe right now?

1 of 3
↑↓to navigateEnterto selectEscto skip

Usage

import {
  SequenceShell,
  useQuestionSequence,
} from "@/components/socratic-ui/question-sequence";
import { SingleSelect } from "@/components/socratic-ui/single-select";
import { MultiSelect } from "@/components/socratic-ui/multi-select";

function MySequence() {
  const seq = useQuestionSequence({
    ids: ["vibe", "tools"],
    onComplete: (answers) => console.log(answers),
  });

  return (
    <SequenceShell
      controller={seq}
      render={(currentId) => {
        switch (currentId) {
          case "vibe":
            return (
              <SingleSelect
                question="What's your vibe right now?"
                options={[{ title: "Building mode" }, { title: "Planning mode" }]}
                {...seq.bind<string | null>("vibe", null)}
              />
            );
          case "tools":
            return (
              <MultiSelect
                question="Which of these are you actively using?"
                options={[{ title: "Claude Code" }, { title: "Todoist" }]}
                {...seq.bind<string[]>("tools", [])}
              />
            );
        }
      }}
    />
  );
}

API Reference

PropTypeDefault
idsrequired

Ordered list of question ids. Drives pagination and keys the transition between steps.

string[]
defaultAnswers

Uncontrolled initial answers map, keyed by question id.

Record<string, unknown>
answers

Controlled answers map. When provided, the hook becomes a pure dispatcher — the consumer owns state.

Record<string, unknown>
onAnswerChange

Fires whenever a question's answer changes, regardless of whether the hook is controlled.

(id: string, value: unknown) => void
onComplete

Fires when the user submits from the terminal question (⌘Enter or the primary button).

(answers: Record<string, unknown>) => void
onClose

Fires when the user closes the sequence via the × button or by pressing Esc on the terminal question.

() => void