Is it possible to get selected text from a Text field?

Basically the title. If a Text field has textSelection enabled, is there anyway to get the text that the user has highlighted?

Text("My text here")
    .textSelection(.enabled)

Ultimately, my goal is to be able to highlight text and apply style to individual characters. Using a TextField would give my app the ability to know what's been highlighted, but then I can't style individual elements. I'd like to be able to do this in SwiftUI without having to drop into TextKit.

struct MyTextEditorView: View {
  @State var myText: String = ""
  @State var textSelection: TextSelection? = nil

  var body: some View {
    TextField("Placehodler", 
                     text: $myText, 
                     selection: $textSelection)
  }
}
Answered by DTS Engineer in 824156022

I don't see any way to retrieve selected text from SwiftUI.Text or render attributed text using TextField, and so would suggest that you file a feedback report – If you do so, please share your report ID here for folks to track.

Best,
——
Ziqiao Chen
 Worldwide Developer Relations.

Accepted Answer

I don't see any way to retrieve selected text from SwiftUI.Text or render attributed text using TextField, and so would suggest that you file a feedback report – If you do so, please share your report ID here for folks to track.

Best,
——
Ziqiao Chen
 Worldwide Developer Relations.

I tried with onChange, but could not extract the string:

  var body: some View {
      TextField("Placehodler",
                text: $myText,
                selection: $textSelection)
      .onChange(of: textSelection) {
          print("change of selection: \(textSelection)")
      }
  }

I get

change of selection: Optional(SwiftUI.TextSelection(indices: SwiftUI.TextSelection.Indices.selection(Range(Swift.String.Index(_rawBits: 131080)..<Swift.String.Index(_rawBits: 393224))), affinity: SwiftUI.TextSelectionAffinity.upstream))

But that leads nowhere.

However, TextSelection doc hints at a way to extract strings, but does not show how to retrieve substrings:

struct SuggestionTextEditor: View {
    @State var text: String = ""
    @State var selection: TextSelection? = nil


    var body: some View {
        VStack {
            TextEditor(text: $text, selection: $selection)
            // A helper view that offers live suggestions based on selection.
            SuggestionsView(
                substrings: getSubstrings(text: text, indices: selection?.indices))
        }
    }


    private func getSubstrings(
        text: String, indices: TextSelection.Indices?
    ) -> [Substring] {
        // Resolve substrings representing the current selection...
    }
}

That let me hope there is a solution…

You can retrieve the selected text in TextField / TextEditor in the following way:

struct ContentView: View {
    @State private var text: String = ""
    @State var textSelection: TextSelection? = nil

    var body: some View {
        TextField(
            "Input text here...",
            text: $text,
            selection: $textSelection
        )
        .onChange(of: textSelection) {
            if let seletion = textSelection {
                if case let .selection(range) = seletion.indices {
                    if !seletion.isInsertion {
                        print("Selected text: \(String(text[range]))")
                    }
                    
                } else if case let .multiSelection(ranges) = seletion.indices {
                    for range in ranges.ranges {
                        print("Selected text: \(String(text[range]))")
                    }
                }
            }
        }
    }
}

This doesn't quite help though because TextField and TextEditor doesn't support attributed string rendering and editing as of today.

Best,
——
Ziqiao Chen
 Worldwide Developer Relations.

Is it possible to get selected text from a Text field?
 
 
Q