Find and replace in iOS and iPadOS 16

Apple introduced a redesigned find and replace experience in iOS and iPadOS 16. In SwiftUI this functionality is automatically supported by TextEditor view.

Screenshot of iPad simulator with a text editor and find and replace interface activated

We also have some new APIs to customize find and replace in our apps.

# Disable replace

We can disable support for replace functionality by applying replaceDisabled() modifier to TextEditor.

struct TextView: View {
    @State private var text = ""
    
    var body: some View {
            TextEditor(text: $text)
                .replaceDisabled()
    }
}

# Disable find and replace

If we want to entirely disable the feature, we can use findDisabled() modifier. It will disable both find and replace and user won't be able to summon the system find UI when interacting with our TextEditor.

struct TextView: View {
    @State private var text = ""
    
    var body: some View {
        TextEditor(text: $text)
            .findDisabled()
    }
}

# Programmatically present system find UI

To programmatically summon the find interface, we can use findNavigator(isPresented:) modifier and pass it a binding to a Boolean value.

struct TextView: View {
    @State private var text = ""
    @State private var showFindUI = false
    
    var body: some View {
        TextEditor(text: $text)
            .findNavigator(isPresented: $showFindUI)
            .toolbar {
                Toggle(isOn: $showFindUI) {
                    Label(
                        "Find",
                        systemImage: "magnifyingglass"
                    )
                }
            }
    }
}

Note that if we want to disable replace inside the find UI that is presented programmatically, we have to make sure that replaceDisabled() is placed closer to TextEditor than findNavigator(isPresented:).

TextEditor(text: $text)
    .replaceDisabled()
    .findNavigator(isPresented: $showFindUI)

If we use findDisabled() in conjunction with findNavigator(isPresented:), setting isPresented binding of the find navigator to true won't do anything, because findDisabled() completely disables the feature.

Find and replace is only supported inside TextEditor at the moment, TextField doesn't have this functionality.

You can find a sample project for this post on GitHub.