Skip to content
This repository was archived by the owner on Dec 11, 2025. It is now read-only.

Commit fff6a96

Browse files
Nobodymaterial-automation
authored andcommitted
Add placeholder support to M3CTextView.
PiperOrigin-RevId: 748701838
1 parent d3a4164 commit fff6a96

File tree

1 file changed

+66
-0
lines changed

1 file changed

+66
-0
lines changed

components/M3CTextField/src/M3CTextView.swift

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,39 @@ public final class M3CTextView: UIView, M3CTextInput {
1212
}
1313
}
1414

15+
/// The text that is displayed when the text view is empty.
16+
@objc public var placeholder: String? {
17+
didSet {
18+
placeholderLabel.text = placeholder
19+
updatePlaceholderVisibility()
20+
}
21+
}
22+
23+
/// The color of the placeholder text.
24+
@objc public var placeholderColor: UIColor? {
25+
didSet {
26+
placeholderLabel.textColor = placeholderColor ?? .gray
27+
}
28+
}
29+
30+
/// The font of the placeholder text.
31+
@objc public var placeholderFont: UIFont? {
32+
didSet {
33+
placeholderLabel.font = placeholderFont ?? textContainer.font
34+
}
35+
}
36+
37+
private lazy var placeholderLabel: UILabel = {
38+
let label = UILabel()
39+
label.translatesAutoresizingMaskIntoConstraints = false
40+
label.font = textContainer.font
41+
label.numberOfLines = 0
42+
label.lineBreakMode = .byWordWrapping
43+
label.isAccessibilityElement = false
44+
label.textColor = .gray
45+
return label
46+
}()
47+
1548
private var controlState: UIControl.State {
1649
if isInErrorState {
1750
return .error
@@ -79,6 +112,9 @@ public final class M3CTextView: UIView, M3CTextInput {
79112
super.init(frame: .zero)
80113

81114
configureStackViews()
115+
addSubview(placeholderLabel)
116+
configurePlaceholderConstraints()
117+
updatePlaceholderVisibility()
82118
textContainer.setContentHuggingPriority(.defaultLow, for: .vertical)
83119
textContainer.setContentCompressionResistancePriority(.required, for: .vertical)
84120
}
@@ -154,6 +190,36 @@ public final class M3CTextView: UIView, M3CTextInput {
154190
super.layoutSubviews()
155191
hideEmptyLabels()
156192
}
193+
194+
private func configurePlaceholderConstraints() {
195+
NSLayoutConstraint.activate([
196+
placeholderLabel.topAnchor.constraint(equalTo: textContainer.topAnchor, constant: 10),
197+
placeholderLabel.leadingAnchor.constraint(equalTo: textContainer.leadingAnchor, constant: 12),
198+
placeholderLabel.trailingAnchor.constraint(
199+
equalTo: textContainer.trailingAnchor, constant: -12),
200+
placeholderLabel.bottomAnchor.constraint(
201+
lessThanOrEqualTo: textContainer.bottomAnchor,
202+
constant: -textContainer.textContainerInset.bottom),
203+
])
204+
}
205+
206+
private func updatePlaceholderVisibility() {
207+
if let placeholderText = placeholder {
208+
placeholderLabel.isHidden = !textContainer.text.isEmpty
209+
textContainer.accessibilityHint = textContainer.text.isEmpty ? placeholderText : nil
210+
} else {
211+
placeholderLabel.isHidden = true
212+
textContainer.accessibilityHint = nil
213+
}
214+
}
215+
216+
// MARK: - UITextViewDelegate
217+
218+
public func textViewDidChange(_ textView: UITextView) {
219+
DispatchQueue.main.async { [weak self] in
220+
self?.updatePlaceholderVisibility()
221+
}
222+
}
157223
}
158224

159225
// MARK: M3CTextView Color Configuration

0 commit comments

Comments
 (0)