Black Friday deal: 30% off our book "Integrating SwiftUI into UIKit apps"! Learn more ...Black Friday deal:30% off "Integrating SwiftUI into UIKit apps" >>

Editable navigation titles in SwiftUI on iOS 16

Starting from iOS and iPadOS 16 we have a new version of the navigationTitle(_:) modifier that accepts a binding to a string. We can use this modifier to let users rename items straight from the navigation title in the toolbar. This functionality could be useful in apps where an item is configurable, similar to a document in document-based apps.

Integrating SwiftUI into UIKit Apps by Natalia Panferova book coverIntegrating SwiftUI into UIKit Apps by Natalia Panferova book cover
Black Friday offer
Our book "Integrating SwiftUI into UIKit apps" is now 30% off!

Discover various ways to adopt SwiftUI in existing UIKit projects and take full advantage of the new iOS 16 frameworks and APIs such as Swift Charts.

The offer is active until the 1st of December.

In this post we will be looking at a simplified example of a note taking application, that displays a note list in the sidebar and a note editor in the detail view.

Screenshot of a simple note taking app on iPad Screenshot of a simple note taking app on iPad

The initial code for the note detail view, where we see a text editor and the note name in the navigation bar, could be the following.

struct NoteView: View {
    @ObservedObject var note: Note
    
    var body: some View {
        TextEditor(text: $note.text)
            .padding()
            .navigationTitle(note.title)
    }
}

We would like to let users rename notes from inside the detail view by typing a new name in the navigation bar title. In iOS 16 we can do that by passing a binding to a string instead of a plain string value to the navigationTitle() modifier. It's important to also set the navigation title display mode to inline, otherwise the editing functionality won't work. To be able to extract the binding from the title string, the title property of the Note object will need to be marked with @Published.

struct NoteView: View {
    @ObservedObject var note: Note
    
    var body: some View {
        TextEditor(text: $note.text)
            .padding()
            .navigationTitle($note.title)
            .navigationBarTitleDisplayMode(.inline)
            .toolbarRole(.editor)
    }
}

class Note: Identifiable, ObservableObject {
    @Published var title: String
    @Published var text: String
    
    var id: UUID
    
    ...
}

By setting the toolbar role to editor in iOS 16 we indicate that we would like users to edit the item in the detail view rather than just browse it. This places the navigation title on the leading edge of the bar leaving space for toolbar buttons in the middle. You can learn more about toolbars in iOS/iPadOS 16 from my previous article Customizable toolbar on iPad in SwiftUI.

When we pass a binding to the navigationTitle() SwiftUI automatically changes the appearance of the title and adds an arrow indicator to show that there are actions available. Pressing on the arrow reveals the rename action that is also added automatically.

Screenshot of the sample notes app showing the rename action in the title menu Screenshot of the sample notes app showing the rename action in the title menu

This functionality works on both iPhone and iPad, but the title is always centered in compact size class, independent of the toolbar role setting.

To make sure that the name of the note updates in the sidebar when the user finishes editing it from the navigation title in the detail view, we should make the list row in the sidebar observe the Note object.

struct NoteListRow: View {
    @ObservedObject var note: Note
    
    var body: some View {
        NavigationLink(value: note.id) {
            HStack {
                Text(note.title)
                Spacer()
            }
        }
    }
}

We already had to mark the title of the Note with @Published to extract a binding for it to pass to the navigationTitle() modifier. Now that the row view is observing the Note, the view will get reevaluated when the title changes.

Screenshot of the sample notes app showing the updated title in the sidebar Screenshot of the sample notes app showing the updated title in the sidebar


You can get the full sample for this post from our GitHub repo.