Skip to content

SwiftUI Conditional Modifier Issue

Conditions in View modifiers can be dangerous: When the condition value changes at runtime, the wrapped content view will lose its identity which can cause lost state and fire transitions. This snippet demonstrates the issue: the inner view (stepper counter) will lose state when the outer condition (isBold) changes. Because of this, many SwiftUI modifiers have a nilable/Bool parameter. Here, .fontWeight(isBold ? .bold : .regular) or, on iOS 26+, .bold(isBold) should be used instead:

swift
// » SwiftUI Garden
// » https://swiftui-garden.com/Misc/SwiftUI-Conditional-Modifier-Issue

import SwiftUI

struct ConditionalModifierIssueExample: View {
    @State private var isBold = false
    @State private var counter = 0

    var body: some View {
        Form {
            Toggle("Make Text Bold", isOn: $isBold)

            ConditionalInnerView()
        }
        // Warning: Bad example to demonstrate the
        // "Conditions in View modifiers are dangerous" issue
        .if(isBold) { content in
            content.bold()
        }
    }
}

struct ConditionalInnerView: View {
    @State private var counter = 0

    var body: some View {
        Stepper("Counter: \(counter)", value: $counter)
    }
}

public extension View {
    /// Applies the given transform if the given condition evaluates to `true`.
    /// - Parameters:
    ///   - condition: The condition to evaluate.
    ///   - transform: The transform to apply to the source `View`.
    /// - Returns: Either the original `View` or the modified `View` if the condition is `true`.
    @ViewBuilder func `if`(_ condition: Bool, @ViewBuilder transform: (Self) -> some View) -> some View {
        if condition {
            transform(self)
        } else {
            self
        }
    }

}

#Preview {
    ConditionalModifierIssueExample()
}