Survey UI

Build a custom survey component styled to your app's design system.

By default, sunboard init wires the built-in <Sunboard.Survey /> — a centered modal that shows every question at once. /sunboard.survey-ui replaces it with a custom component that matches your design system, rendered (by default) as a dedicated /onboarding page with one question — or a small group — per step. The useSurvey() hook owns the data, step navigation, and submit; the skill owns the visual layer. It's the survey counterpart to Checklist UI.

When to use it

  • The built-in modal doesn't match your look.
  • You want onboarding to read as a full "set up your account" page rather than a popup to dismiss.

What happens

  1. Inventories your design system — Tailwind, shadcn, MUI, CSS modules, your button/radio/checkbox/progress primitives, and how dark mode works.
  2. Confirms placement — default is a dedicated /onboarding route, multi-step with a progress bar; a modal or single-screen layout if you prefer.
  3. Writes the component at components/sunboard/onboarding-survey.tsx, rendering the current step from useSurvey() and reusing your own primitives.
  4. Mounts it in sunboard-provider.tsx, replacing <Sunboard.Survey /> (checklist, tours, and hotspots stay as they are).
  5. Previews it against your real app.

The hook contract

Everything you render comes from useSurvey() — copy is already token-interpolated, and the hook drives step navigation and submission:

const {
  visible,       // owed + not yet submitted — render nothing when false
  title,         // pre-interpolated heading
  steps,         // SurveyViewStep[] — authored groups, or one per question
  currentStep,   // render this step's questions
  progress,      // 0..100, by step
  isLastStep,
  canAdvance,    // current step's required questions answered
  next,          // advance, or submit on the last step
  back,
  answers,       // Record<string, unknown>
  setAnswer,     // (key, value) — single-select / text
  toggleAnswer,  // (key, value) — one value of a multi-select
  submit,        // posts answers, then re-bootstraps
} = useSurvey();

Don't reach past the hook

Render from currentStep and let next/back/progress drive the flow — don't hand-roll a step index or per-step validation. The hook's field names are a stable, append-only contract. For imperative work, use useSunboard() separately.

On this page