Reading time: 1 min

This recipe shows how to implement undo and redo with SwiftUI TextField.

The end result looks like this:


This solution works for SwiftUI 2+ (iOS 14+, macOS 11+).

Here's the full recipe:

  1. You can access the view's UndoManager from the environment, using the undoManager key.
  2. The UndoManager's registerUndo method requires a target that needs to be a class, so we'll use a separate @StateObject to hold this info. If you're following MVVM, the View's ViewModel is a perfect place for that.
  3. In the TextField itself, pass a custom Binding that interacts with the UndoManager when the text is changed.

Check out the code for more details:

class ViewModel: ObservableObject {
  @Published var text = ""

  func registerUndo(_ newValue: String, in undoManager: UndoManager?) {
    let oldValue = text
    undoManager?.registerUndo(withTarget: self) { [weak undoManager] target in
      target.text = oldValue // registers an undo operation to revert to old text
      target.registerUndo(oldValue, in: undoManager) // this makes redo possible
    text = newValue // update the actual value

struct UndoTest: View {
  @Environment(\.undoManager) var undoManager
  @StateObject private var model = ViewModel()

  var body: some View {
    VStack(spacing: 20) {
      TextField("Undo/redo test", text: Binding<String>(
        get: {
          model.text // retrieve the value
        }, set: {
          model.registerUndo($0, in: undoManager) // set the value
      Button("Undo") {
      .disabled(undoManager?.canUndo == false)
      Button("Redo") {
      .disabled(undoManager?.canRedo == false)

Next Post Previous Post