Post

Replies

Boosts

Views

Activity

UITextField selects all text on focus when the content is long — how to keep the caret at the end?
I’m building a custom input field using UITextField. When the user taps to focus the field and the text is long, the entire text becomes selected by default. This is the same behavior you can see in iOS Safari’s search field or the Messages app search field. What I want: when the field becomes first responder, the caret should be placed at the end of the text (latest word), without selecting all the text. Here’s the code that builds my text field: public func makeTextField() -> UITextField { let textField = UITextField() textField.autocorrectionType = .no textField.setContentCompressionResistancePriority(.required, for: .horizontal) textField.setContentCompressionResistancePriority(.required, for: .vertical) if #available(iOS 13.0, *) { textField.smartInsertDeleteType = .no } textField.smartQuotesType = .no textField.smartDashesType = .no textField.autocapitalizationType = .none textField.contentMode = .scaleToFill if let font = attributes[.font] as? UIFont { textField.font = font } if let color = attributes[.foregroundColor] as? UIColor { textField.textColor = color } // Truncate long text at the head let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.lineBreakMode = .byTruncatingHead textField.defaultTextAttributes[.paragraphStyle] = paragraphStyle textField.delegate = self textField.backgroundColor = .clear textField.addTarget(self, action: #selector(textFieldDidChange(_:)), for: .editingChanged) return textField } Entire text is selected when focusing the field if the text is long. What I’ve tried Forcing the caret to the end in textFieldDidBeginEditing: func textFieldDidBeginEditing(_ textField: UITextField) { let end = textField.endOfDocument textField.selectedTextRange = textField.textRange(from: end, to: end) } Doing the same asynchronously (next runloop) to avoid the system overriding selection: func textFieldDidBeginEditing(_ textField: UITextField) { DispatchQueue.main.async { let end = textField.endOfDocument textField.selectedTextRange = textField.textRange(from: end, to: end) } } Despite these, the system still selects all text on focus when the string is long/truncated at the head.
2
0
235
Nov ’25