Skip to main content
RapidDev - Software Development Agency
outsystems-tutorial

Building Multi-Step Wizard Forms in OutSystems

Use the OutSystems UI Wizard pattern (Navigation category in the Toolbox) with a Local Variable tracking the current step number. Show each step's content with If widgets bound to CurrentStep = N. Validate fields before calling the Wizard's Next action by checking individual inputs and Form.Valid. Save data only on the final step.

What you'll learn

  • How to add and configure the OutSystems UI Wizard pattern on a screen
  • Managing step navigation with a Local Variable and If widgets
  • Implementing per-step validation before allowing the user to advance
  • Collecting and persisting form data across all steps using Local Variables and a Structure
  • Saving accumulated data to the database only when the user completes the final step
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Intermediate8 min read35-50 minOutSystems 11 and ODCMarch 2026RapidDev Engineering Team
TL;DR

Use the OutSystems UI Wizard pattern (Navigation category in the Toolbox) with a Local Variable tracking the current step number. Show each step's content with If widgets bound to CurrentStep = N. Validate fields before calling the Wizard's Next action by checking individual inputs and Form.Valid. Save data only on the final step.

Multi-Step Wizard Forms in OutSystems

Long forms overwhelm users. The Wizard pattern breaks them into manageable steps with a visual progress indicator. OutSystems UI includes a Wizard block in its Navigation category that handles the step indicator visuals; your job is to wire up the step logic, per-step validation, and state management. This tutorial builds a 3-step employee onboarding form: Personal Info → Employment Details → Review & Submit.

Prerequisites

  • OutSystems UI library referenced in your module (it is included by default in Reactive Web Apps)
  • An Employee entity with fields matching the form data you want to collect
  • Familiarity with Local Variables and Client Actions in Service Studio

Step-by-step guide

1

Add the Wizard block to your screen

In the Interface tab, open your screen. From the Toolbox (left panel), search for 'Wizard' under the Navigation category. Drag the Wizard block onto the canvas. The Wizard block renders a horizontal step progress bar at the top. By default it renders three WizardItem children — each WizardItem represents one step bubble in the indicator. Select each WizardItem → in Properties Panel: - WizardItem 1: Label = 'Personal Info', Step = 1 - WizardItem 2: Label = 'Employment', Step = 2 - WizardItem 3: Label = 'Review', Step = 3 Create a Local Variable on the screen: right-click screen name → Add Local Variable → Name = 'CurrentStep', Type = Integer, Default Value = 1.

Expected result: The screen shows a 3-step progress bar with step labels. Step 1 is highlighted because CurrentStep = 1.

2

Create content containers for each step

Below the Wizard block, add three Container widgets (one per step). Wrap each in an If widget to show/hide based on CurrentStep. In the Widget Tree: add three If widgets stacked vertically. - If 1: Condition = CurrentStep = 1 → True branch contains Container for Personal Info fields - If 2: Condition = CurrentStep = 2 → True branch contains Container for Employment fields - If 3: Condition = CurrentStep = 3 → True branch contains Container for Review & Submit Add appropriate Input widgets inside each Container: - Step 1: FullName (Text), Email (Email), PhoneNumber (Text) - Step 2: Department (Dropdown), StartDate (Date) - Step 3: Summary labels showing collected data + Submit button

typescript
1/* If widget conditions */
2CurrentStep = 1 /* shows Personal Info container */
3CurrentStep = 2 /* shows Employment container */
4CurrentStep = 3 /* shows Review container */

Expected result: Only the Step 1 container is visible at startup. Steps 2 and 3 are hidden. All input widgets in Step 1 are visible and editable.

3

Define Local Variables to hold all form data

Data must persist across steps because each step's content is hidden (not destroyed) when CurrentStep changes. Right-click the screen → Add Local Variable for each field: - FullName: Text - Email: Email - PhoneNumber: Text - DepartmentId: Department Identifier - StartDate: Date Bind each Input and Dropdown widget's Variable property to the matching Local Variable. Because Local Variables persist for the lifetime of the screen session, values entered in Step 1 remain available when you reach Step 3.

Expected result: All input widgets are bound. Entering data in Step 1 and advancing to Step 2 then back to Step 1 shows the entered values are preserved.

4

Add Next/Back navigation buttons with step validation

In each step's Container, add navigation buttons: - Step 1: 'Next' button (no Back needed) - Step 2: 'Back' and 'Next' buttons - Step 3: 'Back' and 'Submit' buttons For the Step 1 Next button → right-click → Add OnClick Client Action. Name it 'Step1Next'. Action flow for Step1Next: Start → If: Length(Trim(FullName)) = 0 [True] → Assign: FullNameInput.Valid = False, FullNameInput.ValidationMessage = 'Full name is required' → End → If: not Form1.Valid [True] → End → Assign: CurrentStep = 2 → End For Back buttons, add a simple Assign: CurrentStep = CurrentStep - 1. The WizardItem Step property must also update — since WizardItem.Step is bound to a fixed integer in the Properties Panel, and the Wizard block's ActiveStep is bound to CurrentStep, the visual indicator updates automatically.

typescript
1/* Step 1 Next validation */
2If: Length(Trim(FullName)) = 0
3
4/* Assign for invalid */
5FullNameInput.Valid = False
6FullNameInput.ValidationMessage = "Full name is required"
7
8/* Advance step */
9CurrentStep = 2
10
11/* Back button Assign */
12CurrentStep = CurrentStep - 1

Expected result: Clicking Next on Step 1 with an empty FullName shows the validation error inline and does not advance. Filling in the data and clicking Next changes CurrentStep to 2 and shows Step 2 content.

5

Build the Review step and final Submit action

In the Step 3 Container, add Expression widgets that display the collected data as a summary for the user to review before submitting: - Label: 'Name:', Expression: FullName - Label: 'Email:', Expression: Email - Label: 'Department:', Expression: GetDepartments.List.Current.Department.Name - Label: 'Start Date:', Expression: FormatDate(StartDate, "MMMM d, yyyy") Add a Submit button → right-click → Add OnClick Client Action. Action flow: Start → CreateEmployee Server Action (pass all collected variables) → Message 'Employee registered successfully!' (Success) → Destination: EmployeeListScreen → End The CreateEmployee Server Action (Logic tab → Server Actions) does the actual database write — only on final submission.

typescript
1/* FormatDate expression for review display */
2FormatDate(StartDate, "MMMM d, yyyy")
3
4/* CreateEmployee input mapping (Server Action) */
5Employee.FullName = FullName
6Employee.Email = Email
7Employee.PhoneNumber = PhoneNumber
8Employee.DepartmentId = DepartmentId
9Employee.StartDate = StartDate

Expected result: Step 3 shows a clean summary of all entered data. Clicking Submit creates the employee record and navigates to the list screen with a success message.

Complete working example

WizardForm_screen_logic.txt
1/* Screen: EmployeeOnboarding
2
3 Local Variables:
4 CurrentStep : Integer = 1
5 FullName : Text = ""
6 Email : Email = ""
7 PhoneNumber : Text = ""
8 DepartmentId : Department Identifier = NullIdentifier()
9 StartDate : Date = NullDate()
10
11 Widget tree (simplified):
12 Wizard (ActiveStep = CurrentStep)
13 WizardItem (Label='Personal Info', Step=1)
14 WizardItem (Label='Employment', Step=2)
15 WizardItem (Label='Review', Step=3)
16 If (CurrentStep = 1)
17 Container Step1
18 Form1
19 Input FullName (Variable=FullName, Mandatory=True)
20 Input Email (Variable=Email, Mandatory=True)
21 Input PhoneNumber (Variable=PhoneNumber)
22 Button 'Next' (OnClick=Step1Next)
23 If (CurrentStep = 2)
24 Container Step2
25 Form2
26 Dropdown Department (Variable=DepartmentId)
27 Input StartDate (Variable=StartDate, Mandatory=True)
28 Button 'Back' (Assign CurrentStep=1)
29 Button 'Next' (OnClick=Step2Next)
30 If (CurrentStep = 3)
31 Container Step3
32 Expression FullName
33 Expression Email
34 Expression FormatDate(StartDate,"MMMM d, yyyy")
35 Button 'Back' (Assign CurrentStep=2)
36 Button 'Submit' (OnClick=SubmitEmployee)
37*/
38
39/* Client Action: Step1Next */
40Start
41 --> If: Length(Trim(FullName)) = 0
42 [True] --> Assign FullNameInput.Valid=False, FullNameInput.ValidationMessage="Full name required" --> End
43 --> If: not Form1.Valid
44 [True] --> End
45 --> Assign: CurrentStep = 2
46 --> End
47
48/* Client Action: Step2Next */
49Start
50 --> If: DepartmentId = NullIdentifier()
51 [True] --> Message "Please select a department" (Warning) --> End
52 --> If: StartDate = NullDate()
53 [True] --> Message "Please enter a start date" (Warning) --> End
54 --> Assign: CurrentStep = 3
55 --> End
56
57/* Client Action: SubmitEmployee */
58Start
59 --> CreateEmployee: FullName, Email, PhoneNumber, DepartmentId, StartDate
60 --> Message: "Employee registered!" (Success)
61 --> Destination: EmployeeListScreen
62 --> End

Common mistakes

Why it's a problem: Using separate screens for each wizard step instead of If widgets on one screen

How to avoid: Separate screens lose Local Variable state between navigation. Keep all wizard steps on one screen and use If widgets controlled by CurrentStep to show/hide content.

Why it's a problem: Checking Form.Valid before setting individual input validation states

How to avoid: Always set individual InputName.Valid = False (with ValidationMessage) before checking Form.Valid. The same pattern applies here as in single-step forms — see the outsystems-form-validation tutorial.

Why it's a problem: Saving data to the database at every step

How to avoid: Writing partial records at each step creates orphaned data if the user abandons the wizard. Collect all data in Local Variables across steps and write once in the final Submit action.

Why it's a problem: Not resetting CurrentStep to 1 when the user submits and the screen is reused

How to avoid: After a successful Submit and navigation, the screen's OnInitialize Client Action does not run again if the user returns via Back. Add Assign: CurrentStep = 1 at the top of the SubmitEmployee action before navigating away.

Best practices

  • Save data to the database only on the final Submit, not incrementally at each step, to prevent orphaned partial records.
  • Bind the Wizard block's ActiveStep to your CurrentStep Local Variable so the visual indicator stays in sync automatically.
  • Validate only the fields in the current step before advancing — do not run Step 2 validation when the user clicks Next on Step 1.
  • Use a Structure to group all form variables into a single typed record when the wizard has more than four or five fields.
  • Add a Cancel button that clears all Local Variables and navigates away, so users can start fresh without stale data.
  • Test the Back navigation to confirm that previously entered data is still present when the user returns to an earlier step.

Still stuck?

Copy one of these prompts to get a personalized, step-by-step explanation.

ChatGPT Prompt

I'm building a 3-step wizard form in OutSystems 11 Reactive Web. The steps are: Personal Info (FullName, Email), Employment Details (DepartmentId dropdown, StartDate), and Review & Submit. Explain how to use the OutSystems UI Wizard pattern, manage CurrentStep with a Local Variable, show/hide step containers with If widgets, validate per-step before advancing, and save data only on the final Submit using a Server Action.

OutSystems Prompt

Create a 3-step wizard form in OutSystems on the EmployeeOnboarding screen. Step 1: Personal Info with FullName (Text, mandatory, min 2 chars) and Email (Email type, mandatory). Step 2: Department dropdown (DepartmentId) and StartDate (Date). Step 3: Review display and Submit button. Use OutSystems UI Wizard block with ActiveStep = CurrentStep Local Variable. Validate Step 1 before advancing and call CreateEmployee Server Action only on final Submit.

Frequently asked questions

Can I navigate directly to a specific step, such as from a URL parameter?

Yes. Add an Input Parameter to the screen (right-click screen → Add Input Parameter → 'InitialStep', Integer). In the screen's OnInitialize Client Action, assign CurrentStep = If(InitialStep > 0, InitialStep, 1). Pass the step number as a URL parameter when navigating to the screen.

How do I save partial wizard progress so users can resume later?

Use a Client Variable (Data tab → Client Variables) to persist the form data across sessions. Assign form field values to the Client Variable at each step transition. On screen load, check if the Client Variable has data and pre-populate the form. Write to the database only on final Submit or when explicitly saving a draft.

Is there a maximum number of wizard steps supported by the OutSystems UI Wizard pattern?

There is no hard limit. The Wizard block renders as many WizardItem children as you add. Practically, more than 6-7 steps becomes unwieldy on mobile screens — consider using a Sidebar or alternative navigation pattern for very long flows.

How do I make the step indicator clickable so users can jump to any step?

By default WizardItems are non-interactive indicators. To make them clickable, add an OnClick event to each WizardItem and in the handler, assign CurrentStep to the target step number only if CurrentStep >= target (users can only go back, not skip ahead). Add validation if you want to block backward navigation too.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation — no strings attached.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.