Migrating to 0.7
Stepper and popover surveys can now step back to a previous question. ConfettiState and Flow gain new optional fields for building custom back-navigation UI, and the submit button now sits inside a button row.
Version 0.7 adds back-navigation to the one-question-at-a-time templates (stepper and popover). A respondent can step back to the previous reachable question, revisit their answer, and step forward again without losing anything they had already typed elsewhere in the survey.
This is gated by a new "Allow respondents to navigate back" setting in the survey editor. It defaults to off for every survey, new or existing, so nothing changes until you turn it on. There is no widget-side override — the survey's own setting is the only place this is configured.
The happy path. If you embed a drop-in template (EmbeddedConfetti,
ModalConfetti, PopoverConfetti, StepperConfetti), you can upgrade with
no code changes. The Back button appears automatically once the survey setting
is on.
Update the package
Install 0.7
npm install @opengovsg/confetti@^0.7.0
# or
pnpm add @opengovsg/confetti@^0.7.0
# or
yarn add @opengovsg/confetti@^0.7.0Update your code if you build your own survey UI
Only callers driving ConfettiController or Flow directly need changes, and
only if they want to render a Back button of their own.
Every change below is additive — existing code keeps compiling and behaving
the same. See Are you affected?.
Are you affected?
No changes if you use a drop-in template. The stepper and popover templates render the Back button internally once the survey's setting allows it.
You only need to update your code if you render ConfettiController or
Flow yourself and want a Back button in your own UI.
Nothing is removed; the new fields are optional additions.
Building-block changes (@opengovsg/confetti/components)
ConfettiState gains back-navigation fields
back()— steps to the previous reachable question. A no-op when already at the first reachable question, or when the survey's setting disallows it.canGoBack— whether a previous reachable question exists to step back to.answers— every answer entered so far, keyed by question id, including answers to questions that are momentarily unreachable after a reroute.saveAnswer(question, answer)— records a question's in-progress answer without validating, navigating, or auto-submitting. A plain draft-save, used so a respondent who leaves via Back keeps what they typed even though they never pressed Next/Submit.backButtonLabel— the survey's custom label for the Back button, orundefinedto use your own default.
BackButton is a new export
import { BackButton } from '@opengovsg/confetti/components'A minimal styled button (onPress, with children defaulting to "Back")
that hides itself while a bug-report screen recording is in progress.
You are not required to use it — any pressable element calling back() works.
Flow gains defaultAnswer, backButton, and saveAnswer props
FlowProps accepts three new optional props, and the child render function
now also receives defaultAnswer:
defaultAnswer— the prior answer for this question, seeding the field so a revisited question shows what was previously entered.backButton— aReactNoderendered alongside the submit button in a single row.Flowwraps itsonPressto flush the in-progress answer viasaveAnswerbefore it fires, so leaving through Back never drops a draft.saveAnswer— the draft-save callback described above, called with the in-progress answer.
Wiring it up looks like this (adapted from the stepper template):
<Flow
question={currentQuestion}
isLastQuestion={isLastQuestion}
defaultAnswer={answers[currentQuestion.id] ?? undefined}
backButton={
canGoBack ? (
<BackButton onPress={back}>{backButtonLabel}</BackButton>
) : undefined
}
saveAnswer={(answer) => saveAnswer(currentQuestion.id, answer)}
onSubmit={(answer) => update({ question: current, answer })}
>
{({ onChange, question, error, defaultAnswer }) => (
<SurveyQuestionFactory
onChange={onChange}
question={question}
error={error}
defaultAnswer={defaultAnswer}
/>
)}
</Flow>If you don't pass backButton, Flow renders exactly as it did in 0.6.
Question components gain defaultAnswer
BaseFieldProps (and every question component built on it — FreeText,
MultiChoice, Rating, SingleChoice, SurveyQuestionFactory, …) accepts an
optional defaultAnswer used to seed the field's initial value.
Omit it and the field starts empty, exactly as before.
Styling changes
The submit button moved from a direct flex child of the question container
into a new .cf-button-row wrapper. If you have custom CSS targeting
.cf-submit-button's position (for example an align-self or margin override
assuming it sits directly in the question's flex column), check it still reads
correctly against .cf-button-row.
Both buttons now render inside .cf-button-row, a flex row that keeps the
submit button flush right whether or not a Back button is present alongside
it. A new --confetti-button-row-gap custom property (default 16px)
controls the gap between them:
.confetti {
--confetti-button-row-gap: 12px;
}The Back button itself renders as .cf-back-button, styled as a text button
using your theme's --confetti-text-primary-color and
--confetti-outline-color.
Need help?
- See when to show the survey for examples that use the building blocks.
- Email confetti@open.gov.sg
- Slack #confetti (internal use only)
Was this page helpful?