I recently had the challenge to design a wizard user interface in Appian. But it was not that ordinary wizard with just a few static steps. It had to be a wizard with a dynamic dumber of steps.
When looking at this from a UX perspective, I wanted to avoid surprising the user with a wizard where the number of steps changes while entering data.
So I had to be creative.
An Idea
If I could find a way to add an initial step to the wizard in which I ask the user for all the data I need to determine which steps to show in the wizard. Making this the first step in a wizard layout would still result in steps randomly showing up or vanishing.
But, when I combine two layouts, I could create that initial screen using a normal form layout, and then switch to a wizard layout for which I then know exactly which steps to show. And no awkward UX.
How it Looks
This is just a simple example I made up to demo the pattern.

The wizard shows up to three dynamic steps, and a final static summary step.

By using the same title, secondary text, and styling for the form layout and the wizard layout, the user does experience a uniform design.

The Code
There is one simple trick to make this work. Appian does not allow a list of top-level layout components. So I used an if() statement to switch between the two. The match() function would work as well.
And keep in mind, that you might want to split such an interface into separate interfaces for each step for easy collaborative development and maintainability.
a!localVariables(
local!mode: "INITIAL",
local!activeSteps: {1, 2, 3},
if(
local!mode = "INITIAL",
a!formLayout(
titleBar: a!headerTemplateFull(
title: "Form",
secondaryText: "Enter your details",
),
contents: {
a!checkboxFieldByIndex(
label: "Active Wizard Steps",
choiceLabels: {"Separate Delivery Address", "Payment Method", "Coupons"},
value: local!activeSteps,
saveInto: local!activeSteps
)
},
buttons: a!buttonLayout(
primaryButtons: {
a!buttonWidget(
label: "Next",
submit: false,
style: "SOLID",
value: "WIZARD",
saveInto: local!mode
)
},
secondaryButtons: {
a!buttonWidget(
label: "Cancel",
value: true,
saveInto: {},
submit: true,
style: "OUTLINE",
validate: false
)
}
)
),
a!wizardLayout(
titleBar: a!headerTemplateFull(
title: "Form",
secondaryText: "Enter your details",
backgroundColor: "ACCENT"
),
showTitleBarDivider: false,
secondaryButtons: {
a!buttonWidget(
label: "Back",
value: "INITIAL",
saveInto: local!mode,
showWhen: fv!isFirstStep
)
},
primaryButtons: {
a!buttonWidget(
label: "Submit",
showWhen: fv!isLastStep,
style: "SOLID"
)
},
steps: {
a!wizardStep(
label: "Separate Delivery Address",
showWhen: contains(local!activeSteps, 1),
contents: {
a!richTextDisplayField(
labelPosition: "COLLAPSED",
value: a!richTextItem(
text: "Wizard step content ..."
)
)
}
),
a!wizardStep(
label: "Payment Method",
showWhen: contains(local!activeSteps, 2),
contents: {
a!richTextDisplayField(
labelPosition: "COLLAPSED",
value: a!richTextItem(
text: "Wizard step content ..."
)
)
}
),
a!wizardStep(
label: "Coupons",
showWhen: contains(local!activeSteps, 3),
contents: {
a!richTextDisplayField(
labelPosition: "COLLAPSED",
value: a!richTextItem(
text: "Wizard step content ..."
)
)
}
),
a!wizardStep(
label: "Summary",
contents: {
a!richTextDisplayField(
labelPosition: "COLLAPSED",
value: a!richTextItem(
text: "Wizard step content ..."
)
)
}
),
},
)
)
)
Final Words
Combining multiple high-level layouts is not directly supported, but can still be used to provide a superior UX to our precious users.
Rock it!
