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

Conditional Logic: If Widget, Switch Widget, and Expression Patterns

OutSystems has three ways to express conditional logic: the If widget on screens (shows/hides UI based on a Boolean expression), the If node in action flows (branches logic), and the If() function in expressions (inline ternary). The Switch node handles multiple-branch conditions in action flows, equivalent to a switch/case statement.

What you'll learn

  • How to use the If widget on a screen to conditionally show or hide UI sections
  • Using the If node in action flows to branch logic in Client and Server Actions
  • Writing inline conditional expressions with the If() function
  • Using the Switch node for multi-branch conditions in action flows
  • Combining nested If expressions for complex business rules
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Beginner9 min read20-25 minOutSystems 11 and ODCMarch 2026RapidDev Engineering Team
TL;DR

OutSystems has three ways to express conditional logic: the If widget on screens (shows/hides UI based on a Boolean expression), the If node in action flows (branches logic), and the If() function in expressions (inline ternary). The Switch node handles multiple-branch conditions in action flows, equivalent to a switch/case statement.

Conditional Logic in OutSystems

OutSystems provides conditional logic at three levels: the screen layout (If widget), the action flow (If node and Switch node), and inline expressions (If() function). Understanding which tool to use where — and the important OutSystems-specific syntax differences from JavaScript — eliminates the most common beginner mistakes and TrueChange errors.

Prerequisites

  • Service Studio with a Reactive Web App open
  • A screen with at least one Local Variable and one widget
  • Familiarity with the Screen Editor and Action Flow Editor

Step-by-step guide

1

Use the If widget to conditionally show UI on a screen

The If widget is a layout element that renders either its True branch or False branch based on a Boolean expression. It does NOT hide the element with CSS — it removes it from the DOM when False. In the Screen Editor, search the Toolbox for 'If' and drag it onto the canvas. In the Properties Panel: - Condition: enter your Boolean expression, e.g. User.IsLoggedIn The Widget Tree shows two branches inside the If widget: True Branch and False Branch. Drag UI elements into each branch. Only the branch matching the condition is rendered. Common use cases: - Show 'Admin' menu only if CheckAdminRole() = True - Show loading spinner while data fetches: GetEmployees.IsLoading - Hide empty state message: not GetEmployees.List.Empty - Conditional form sections: SelectedCountry = Entities.Country.US

typescript
1/* If widget condition examples */
2User.IsLoggedIn
3CheckAdminRole()
4not GetEmployees.List.Empty
5CurrentStep = 3
6Order.Status = Entities.OrderStatus.Pending
7SelectedCountryId <> NullIdentifier()
8GetOrders.IsLoading

Expected result: The True branch content is visible and the False branch is completely absent from the rendered HTML when the condition is False.

2

Use the If node in action flows for branching logic

In the Action Flow Editor (for both Client and Server Actions), the If node creates a binary branch. Drag 'If' from the Toolbox onto the flow between two nodes. The If node has: - Condition (Boolean expression): set in Properties Panel - True connector (right side): flow when condition is True - False connector (bottom): flow when condition is False Example — save or navigate based on form validity: Start → If: Form.Valid → [True] SaveEmployee Server Action → Destination → [False] End Nesting: connect multiple If nodes in sequence. The False branch of one If can connect to the next If node for an else-if chain: Start → If: Status = 'Active' → [True] ... → [False] → If: Status = 'Pending' → [True] ... → [False] → end default case

typescript
1/* Action flow with nested If nodes */
2Start
3 --> If: Order.TotalAmount > 1000
4 [True] --> Assign: DiscountRate = 0.15
5 [False] --> If: Order.TotalAmount > 500
6 [True] --> Assign: DiscountRate = 0.10
7 [False] --> Assign: DiscountRate = 0.05
8 --> Assign: FinalAmount = Order.TotalAmount * (1 - DiscountRate)
9 --> End

Expected result: The action flow branches correctly at runtime. Set a breakpoint on the If node in the Debugger to verify which branch executes.

3

Use the If() function for inline conditional expressions

The If() function returns one of two values based on a condition. Use it anywhere an expression is expected — widget properties, Assign node values, Aggregate filter conditions, FormatDate arguments. Syntax: If(BooleanCondition, TrueValue, FalseValue) Critical rule: TrueValue and FalseValue MUST be the same data type. OutSystems does not auto-cast — passing a Text True value and an Integer False value causes a TrueChange type error. Examples: - If(Employee.IsActive, "Active", "Inactive") → Text - If(Order.Amount > 100, Order.Amount * 0.9, Order.Amount) → Decimal - If(User.Age >= 18, True, False) → same as just User.Age >= 18 - If(GetOrder.IsLoading, "Loading...", IntegerToText(GetOrder.List.Length) + " orders") → Text

typescript
1/* If() expression examples */
2
3/* Text conditional */
4If(Employee.IsActive, "Active", "Inactive")
5
6/* Decimal conditional */
7If(Order.Amount > 100, Order.Amount * 0.9, Order.Amount)
8
9/* Nested If() - equivalent to else-if */
10If(Age >= 65, "Senior", If(Age >= 18, "Adult", "Minor"))
11
12/* Used in FormatDate */
13FormatDate(If(Order.ShippedDate = NullDate(), CurrDate(), Order.ShippedDate), "dd/MM/yyyy")
14
15/* Used in Aggregate filter */
16Order.Status = If(ShowAllOrders, Entities.OrderStatus.All, Entities.OrderStatus.Pending)
17
18/* Conditional CSS class */
19If(IsSelected, "selected active", "")

Expected result: Expressions using If() compile without TrueChange errors. The Expression widget on screen dynamically shows 'Active' or 'Inactive' based on Employee.IsActive.

4

Use the Switch node for multi-branch conditions in action flows

The Switch node is the OutSystems equivalent of a switch/case statement. Use it when you have three or more branches based on the same value. Drag 'Switch' from the Toolbox into an action flow. In the Properties Panel, add cases: - Click '+' for each case - Case 1: Expression = Order.Status = Entities.OrderStatus.Pending, connect to 'Send pending reminder' logic - Case 2: Expression = Order.Status = Entities.OrderStatus.Shipped, connect to 'Send tracking email' logic - Case 3: Expression = Order.Status = Entities.OrderStatus.Cancelled, connect to 'Send cancellation notice' logic - Otherwise (default): connect to logging or no-op End Switch evaluates cases top-to-bottom and takes the FIRST match. Unlike some languages, there is no fallthrough — only one branch executes. When to use Switch over nested Ifs: - 3+ branches on the same variable → Switch - 2 branches or unrelated conditions → If node chain

typescript
1/* Switch node cases - evaluates top to bottom, first match wins */
2Case 1: Order.Status = Entities.OrderStatus.Pending
3 --> Send pending reminder email
4Case 2: Order.Status = Entities.OrderStatus.Shipped
5 --> Send tracking number SMS
6Case 3: Order.Status = Entities.OrderStatus.Cancelled
7 --> Send cancellation refund notice
8Otherwise:
9 --> LogMessage: "Unhandled order status: " + Order.Status

Expected result: The action flow executes the matching case branch. Only one branch fires per execution regardless of how many cases exist.

5

Apply conditional logic to widget properties beyond Visible

The If widget handles conditional rendering, but you can also apply conditional logic to any widget property that accepts an expression: - Style Classes: If(IsHighlighted, "highlight-row", "") — applies a CSS class conditionally - Enabled: SelectedCountryId <> NullIdentifier() — disables a button until a precondition is met - Mandatory: If(RequiresPhone, True, False) — makes a field mandatory based on context - Value in Expression widget: If(Employee.IsActive, "Active", "Inactive") — text content For Button Enabled, set the Enabled expression in the Button's Properties Panel: Enabled = Form.Valid and SelectedCountryId <> NullIdentifier() This creates a reactive UI where the button only becomes clickable when the form is valid and a country is selected — no Client Action needed.

typescript
1/* Widget property conditional expressions */
2
3/* Button Enabled */
4Form.Valid and SelectedCountryId <> NullIdentifier()
5
6/* Input Mandatory */
7If(DeliveryMethod = Entities.DeliveryMethod.Home, True, False)
8
9/* Dynamic CSS class */
10If(Row.IsOverdue, "row-overdue text-danger", "")
11
12/* List item background color via Style Class */
13If(Mod(GetEmployees.List.CurrentRowNumber, 2) = 0, "row-even", "row-odd")

Expected result: Widget properties update reactively as the bound variables change, without requiring Client Action logic for simple show/disable/style patterns.

Complete working example

ConditionalLogic_patterns.txt
1/* ============================================================
2 IF WIDGET PATTERNS (Screen Editor)
3 ============================================================ */
4
5If (Condition = User.IsAdmin)
6 True Branch: Admin Dashboard Container
7 False Branch: Standard User Dashboard Container
8
9If (Condition = GetOrders.IsLoading)
10 True Branch: Spinner widget
11 False Branch: If (not GetOrders.List.Empty)
12 True: Table widget bound to GetOrders.List
13 False: BlankSlate 'No orders found'
14
15/* ============================================================
16 IF NODE PATTERNS (Action Flows)
17 ============================================================ */
18
19/* Client Action: ApplyDiscount */
20Start
21 --> If: Order.TotalAmount > 1000
22 [True] --> Assign: DiscountRate = 0.15
23 [False] --> If: Order.TotalAmount > 500
24 [True] --> Assign: DiscountRate = 0.10
25 [False] --> Assign: DiscountRate = 0.05
26 --> Assign: FinalAmount = Order.TotalAmount * (1 - DiscountRate)
27 --> End
28
29/* ============================================================
30 IF() EXPRESSION PATTERNS
31 ============================================================ */
32
33/* Inline ternary for display */
34If(Employee.IsActive, "Active", "Inactive")
35
36/* Nested If() for three outcomes */
37If(Score >= 90, "A", If(Score >= 70, "B", If(Score >= 50, "C", "F")))
38
39/* Null safety pattern */
40If(Order.ShippedDate = NullDate(), "Not yet shipped",
41 "Shipped: " + FormatDate(Order.ShippedDate, "dd/MM/yyyy"))
42
43/* ============================================================
44 SWITCH NODE PATTERN
45 ============================================================ */
46Switch on Order.Status:
47 Pending --> send reminder
48 Shipped --> send tracking info
49 Delivered --> request review
50 Cancelled --> process refund
51 Otherwise --> log unknown status

Common mistakes

Why it's a problem: Using If(condition, True, False) when just 'condition' works

How to avoid: If the TrueValue is True and FalseValue is False, the If() call is redundant. Use the Boolean expression directly: Button.Enabled = IsFormValid is cleaner than Button.Enabled = If(IsFormValid, True, False).

Why it's a problem: Mismatched types in If() expression (Text True value, Integer False value)

How to avoid: TrueChange will show 'Invalid data type' error. Ensure both values are the same type. Use IntegerToText() or TextToInteger() to convert. Example: If(IsNew, "New", IntegerToText(RecordCount)) — both are now Text.

Why it's a problem: Using a Screen Aggregate inside an If widget condition that runs before data loads

How to avoid: Use GetEmployees.IsLoading and GetEmployees.List.Empty to handle loading and empty states. Wrap the data-dependent If condition in an outer If checking IsLoading first to prevent accessing .List.Current on an empty list.

Why it's a problem: Placing the If node's False branch logic above the True branch in the flow visually

How to avoid: In Service Studio's Action Flow Editor, the True connector goes right and the False connector goes down by default. When arranging complex flows, keep the happy path going right and exception/alternative paths going down for readability — this matches the visual convention OutSystems developers expect.

Best practices

  • Use the If widget (not CSS visibility) for conditional rendering of substantial UI sections — it removes the element from the DOM and avoids rendering overhead.
  • Use Switch nodes when you have three or more branches on the same variable — it is more readable and maintainable than chained If nodes.
  • Keep If() expression nesting to two levels maximum. Three or more nested If() calls should be moved to a Assign node in an action flow or a local Server Action function.
  • Both values in an If() expression must be the same data type — use conversion functions (IntegerToText, TextToInteger) if needed.
  • For widget Enabled and Mandatory properties, use direct Boolean expressions rather than If(condition, True, False) — If(x, True, False) is identical to just x.
  • Add an Otherwise branch to every Switch node to handle unexpected values — log the unhandled case to Service Center for debugging.

Still stuck?

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

ChatGPT Prompt

Explain the three types of conditional logic in OutSystems: the If widget (screen layout), the If node (action flows), and the If() function (expressions). Show examples of each with OutSystems expression syntax. Include a Switch node example for multi-branch logic and explain the TrueValue/FalseValue type-matching rule in If() expressions.

OutSystems Prompt

Add conditional logic to my OutSystems employee list screen: (1) If widget showing a BlankSlate when GetEmployees.List.Empty is True, (2) If widget showing an 'Admin only' section when CheckAdminRole() is True, (3) Expression widget showing employee status as 'Active' or 'Inactive' using the If() function on Employee.IsActive, (4) Submit button Enabled property set to Form.Valid and SelectedDeptId <> NullIdentifier().

Frequently asked questions

What is the difference between the If widget and setting Visible = False on a widget?

The If widget completely removes the non-rendered branch from the DOM. Setting Visible = False hides the element but leaves it in the DOM. Use If widget for conditional content that should not be rendered at all (cleaner HTML, better performance). Use Visible = False for elements that need to toggle frequently with animation or when keeping the DOM position matters.

Can I use the Switch node in a Client Action, or only in Server Actions?

The Switch node is available in both Client Actions and Server Actions. Drag it from the Toolbox in the Action Flow Editor for either action type. The behavior is identical regardless of execution context.

How do I express an 'and' / 'or' condition in an OutSystems expression?

OutSystems uses lowercase 'and' and 'or' operators (not && or ||). Example: Employee.IsActive and Employee.DepartmentId = SelectedDeptId. For negation, use 'not': not Employee.IsActive. These are OutSystems expression keywords, not JavaScript operators.

Is there a null/nil check equivalent in OutSystems expressions?

Yes, but it depends on the type. For entity identifiers: use = NullIdentifier() or = NullTextIdentifier(). For dates: = NullDate(). For binary data: = NullBinaryData(). For text: = '' (empty string — OutSystems has no null text). For integers: = 0 (the default, not null). OutSystems intentionally avoids null for most types to prevent null reference exceptions.

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.