603

I'd like to change the color of the placeholder text I set in my UITextField controls, to make it black.

I'd prefer to do this without using normal text as the placeholder and having to override all the methods to imitate the behaviour of a placeholder.

I believe if I override this method:

- (void)drawPlaceholderInRect:(CGRect)rect 

then I should be able to do this. But I'm unsure how to access the actual placeholder object from within this method.

0

32 Answers 32

818

Since the introduction of attributed strings in UIViews in iOS 6, it's possible to assign a color to the placeholder text like this:

if ([textField respondsToSelector:@selector(setAttributedPlaceholder:)]) { UIColor *color = [UIColor blackColor]; textField.attributedPlaceholder = [[NSAttributedString alloc] initWithString:placeholderText attributes:@{NSForegroundColorAttributeName: color}]; } else { NSLog(@"Cannot set placeholder text's color, because deployment target is earlier than iOS 6.0"); // TODO: Add fall-back code to set placeholder color. } 
Sign up to request clarification or add additional context in comments.

16 Comments

This is good - but remember you need to set a placeholder value in IB before this will work
its also worth wrapping this in a respondsToSelector call - as without it this code will crash on pre 6.0 deployment target ( unrecognized selector sent to instance)
The docs for the attributedPlaceholder says that is uses text attributes, except for colour.
Any idea why it's not working for the attribute - NSFontAttributeName [[NSAttributedString alloc] initWithString:@"placeholder" attributes: @{NSForegroundColorAttributeName: color, NSFontAttributeName : font}];
On iOS 7 I got this error: [<UITextField 0x11561d90> valueForUndefinedKey:]: this class is not key value coding-compliant for the key _field.
|
239

Easy and pain-free, could be an easy alternative for some.

_placeholderLabel.textColor 

Not suggested for production, Apple may reject your submission.

11 Comments

Are you using this in production? I mean to access a private property.
Maybe add the text to your answer for fast copy and paste. _placeholderLabel.textColor
Don't use this method, i have used this and itune store, has rejected my application.
I think any kind of private library method should NEVER be recommended as solution to anything
@jungledev _placeholderLabel is a private property. This solution is subject to being rejected for use of private API.
|
197

You can override drawPlaceholderInRect:(CGRect)rect as such to manually render the placeholder text:

- (void) drawPlaceholderInRect:(CGRect)rect { [[UIColor blueColor] setFill]; [[self placeholder] drawInRect:rect withFont:[UIFont systemFontOfSize:16]]; } 

9 Comments

Something like [self.placeholder drawInRect:rect withFont:self.font lineBreakMode:UILineBreakModeTailTruncation alignment:self.textAlignment]; is probably better. That way you will respect the textAlignment property. I have added this to my SSTextField class. Feel free to use in your projects.
Absolutely do NOT do what Koteg said. NEVER override methods through categories. EVER
@JoshuaWeinberg Is there any specific reason behind your sugestion.
@Krishnan implementing a duplicate method in a category is not supported, and you can never be certain which method will be called, or if both with be called, or the order in which they will be called.
In iOS7 you can alter the rect by using CGRectInset(rect, 0, (rect.size.height - self.font.lineHeight) / 2.0) to vertically center the text.
|
184

This works in Swift <3.0:

myTextField.attributedPlaceholder = NSAttributedString(string: "placeholder text", attributes: [NSForegroundColorAttributeName : UIColor.redColor()]) 

Tested in iOS 8.2 and iOS 8.3 beta 4.

Swift 3:

myTextfield.attributedPlaceholder = NSAttributedString(string: "placeholder text", attributes: [NSForegroundColorAttributeName : UIColor.red]) 

Swift 4:

myTextfield.attributedPlaceholder = NSAttributedString(string: "placeholder text", attributes: [NSAttributedStringKey.foregroundColor: UIColor.red]) 

Swift 4.2:

myTextfield.attributedPlaceholder = NSAttributedString(string: "placeholder text", attributes: [NSAttributedString.Key.foregroundColor: UIColor.red]) 

1 Comment

Using your solution on iOS8.2, works like a charm. Perfect solution here. Using in objective C also.
176

You can Change the Placeholder textcolor to any color which you want by using the below code.

UIColor *color = [UIColor lightTextColor]; YOURTEXTFIELD.attributedPlaceholder = [[NSAttributedString alloc] initWithString:@"PlaceHolder Text" attributes:@{NSForegroundColorAttributeName: color}]; 

8 Comments

Best answer suggested. Works, and uses documented APIs.
How do you make this work for UISearchBar? There is no attributedPlaceholder property.
This answer is not correct – according to the docs, the text color information of attributedPlaceholder is ignored developer.apple.com/library/ios/documentation/UIKit/Reference/…
Thanks everyone. Hope it was of some help. Adlai Holler give it a try bro!!! This answer was for the previous version of iOS. If you have better answer we are open to suggestions.
Doesn't work on iOS8 as there's no attributedPlaceholder property
|
157

Maybe you want to try this way, but Apple might warn you about accessing private ivar:

[self.myTextField setValue:[UIColor darkGrayColor] forKeyPath:@"_placeholderLabel.textColor"]; 

NOTE
This is not working on iOS 7 anymore, according to Martin Alléus.

15 Comments

I use this method in my app. The review was OK. So I think it's fine to use it.
This is not app store safe and should not be encouraged, you're not guaranteed to get approved or stay in approved with these techniques.
It shouldn't really matter if it's approved or not really. The important thing is that this could break your app in future OS updates.
Not having any problem with iOS 7... I gave it a try despite the note and it seems to work fine and I've used this approach in the past with no problems.
This was always a bad idea, and now it's broken on iOS 13: Access to UITextField's _placeholderLabel ivar is prohibited. This is an application bug 😈
|
96

Swift 3.0 + Storyboard

In order to change placeholder color in storyboard, create an extension with next code. (feel free to update this code, if you think, it can be clearer and safer).

extension UITextField { @IBInspectable var placeholderColor: UIColor { get { guard let currentAttributedPlaceholderColor = attributedPlaceholder?.attribute(NSForegroundColorAttributeName, at: 0, effectiveRange: nil) as? UIColor else { return UIColor.clear } return currentAttributedPlaceholderColor } set { guard let currentAttributedString = attributedPlaceholder else { return } let attributes = [NSForegroundColorAttributeName : newValue] attributedPlaceholder = NSAttributedString(string: currentAttributedString.string, attributes: attributes) } } } 

enter image description here

Swift 4 version

extension UITextField { @IBInspectable var placeholderColor: UIColor { get { return attributedPlaceholder?.attribute(.foregroundColor, at: 0, effectiveRange: nil) as? UIColor ?? .clear } set { guard let attributedPlaceholder = attributedPlaceholder else { return } let attributes: [NSAttributedStringKey: UIColor] = [.foregroundColor: newValue] self.attributedPlaceholder = NSAttributedString(string: attributedPlaceholder.string, attributes: attributes) } } } 

Swift 5 version

extension UITextField { @IBInspectable var placeholderColor: UIColor { get { return attributedPlaceholder?.attribute(.foregroundColor, at: 0, effectiveRange: nil) as? UIColor ?? .clear } set { guard let attributedPlaceholder = attributedPlaceholder else { return } let attributes: [NSAttributedString.Key: UIColor] = [.foregroundColor: newValue] self.attributedPlaceholder = NSAttributedString(string: attributedPlaceholder.string, attributes: attributes) } } } 

2 Comments

The compiler can't find out NSAttributedStringKey.
Works in iOS 13
78

In Swift:

if let placeholder = yourTextField.placeholder { yourTextField.attributedPlaceholder = NSAttributedString(string:placeholder, attributes: [NSForegroundColorAttributeName: UIColor.blackColor()]) } 

In Swift 4.0:

if let placeholder = yourTextField.placeholder { yourTextField.attributedPlaceholder = NSAttributedString(string:placeholder, attributes: [NSAttributedStringKey.foregroundColor: UIColor.black]) } 

4 Comments

If you didn't set the placeholder text before calling that it will crash the app
This is the best one, thank you. @apinho nothing will crash here
//In Swift 4 if let placeholder = yourTextField.placeholder { yourTextField.attributedPlaceholder = NSAttributedString(string:placeholder, attributes: [NSAttributedStringKey.foregroundColor: UIColor.white]) }
Beware that changing the placeholder text value after this code has been executed will bring back the default placeholder color.
43

The following only with iOS6+ (as indicated in Alexander W's comment):

UIColor *color = [UIColor grayColor]; nameText.attributedPlaceholder = [[NSAttributedString alloc] initWithString:@"Full Name" attributes:@{NSForegroundColorAttributeName:color}]; 

Comments

36

I had already faced this issue. In my case below code is correct.

Objective C

[textField setValue:[UIColor whiteColor] forKeyPath:@"_placeholderLabel.textColor"]; 

For Swift 4.X

tf_mobile.setValue(UIColor.white, forKeyPath: "_placeholderLabel.textColor") 

For iOS 13 Swift Code

tf_mobile.attributedPlaceholder = NSAttributedString(string:"PlaceHolder Text", attributes: [NSAttributedString.Key.foregroundColor: UIColor.red]) 

You can also use below code for iOS 13

let iVar = class_getInstanceVariable(UITextField.self, "_placeholderLabel")! let placeholderLabel = object_getIvar(tf_mobile, iVar) as! UILabel placeholderLabel.textColor = .red 

Hope, this may help you.

6 Comments

@Ashu this causes crash in ios 13 'Access to UITextField's _placeholderLabel ivar is prohibited. This is an application bug' it wont be even build I am not talking about placing into AppStore
IOS 13 this was restricted can't use this anymore
@Mehdico I updated the answer for iOS 13. Hope this will helps you.
Took me far too long to learn that I had to make this change in viewWillAppear or viewDidAppear. viewDidLoad is too early.
I had to use UIColor(displayP3Red: 255, green: 255, blue: 255, alpha: 0.3) constructor for UIColor instead of UIColor(red: 255, green: 255, blue: 255, alpha: 0.3)
|
32

With this we can change the color of textfield's placeholder text in iOS

[self.userNameTxt setValue:[UIColor colorWithRed:41.0/255.0 green:91.0/255.0 blue:106.0/255.0 alpha:1.0] forKeyPath:@"_placeholderLabel.textColor"]; 

2 Comments

@Teddy how did you do it now? I started to have problems with this.
@Jalil I hope I am still on time for you. textField.attributedPlaceholder = [[NSAttributedString alloc] initWithString:@"text" attributes:@{NSForegroundColorAttributeName:[UIColor colorWithHexString:@"ffffff55"]}];
30

in swift 3.X

textField.attributedPlaceholder = NSAttributedString(string: "placeholder text", attributes:[NSForegroundColorAttributeName: UIColor.black]) 

in swift 5

textField.attributedPlaceholder = NSAttributedString(string: "placeholder text", attributes: [NSAttributedString.Key.foregroundColor : UIColor.black]) 

Comments

22

Why don't you just use UIAppearance method:

[[UILabel appearanceWhenContainedIn:[UITextField class], nil] setTextColor:[UIColor whateverColorYouNeed]]; 

2 Comments

Works great! Color of text doesn't affected (At least with different proxy for textColor property)
Great worked but showing warning for this method
18

Also in your storyboard, without single line of code

enter image description here

5 Comments

How come you know this? It is best approach i think but how one can know this? Please tell i am new to ios programming.
It's very universal. Once you know it use it everywhere ;)
I know once I understand whats running behind it i am going to use it a lot. But I mean "_placeholderLabel.textColor" this should be a child view of textfield. Is there a way to see this type of information about a control?
@Yawar You can use the view hierarchy inspector in Xcode, or introspect the view in the debugger.
good one, regardless of textfield, you can use the same 'tile/name' for keypath
12

For iOS 6.0 +

[textfield setValue:your_color forKeyPath:@"_placeholderLabel.textColor"]; 

Hope it helps.

Note: Apple may reject (0.01% chances) your app as we are accessing private API. I am using this in all my projects since two years, but Apple didn't ask for this.

1 Comment

throws a terminating with uncaught exception of type NSException for iOS8
10

Swift version. Probably it would help someone.

class TextField: UITextField { override var placeholder: String? { didSet { let placeholderString = NSAttributedString(string: placeholder!, attributes: [NSForegroundColorAttributeName: UIColor.whiteColor()]) self.attributedPlaceholder = placeholderString } } } 

Comments

10

For Xamarin.iOS developers, I found it from this document https://developer.xamarin.com/api/type/Foundation.NSAttributedString/

textField.AttributedPlaceholder = new NSAttributedString ("Hello, world",new UIStringAttributes () { ForegroundColor = UIColor.Red }); 

1 Comment

Thank you !! I was first using CTStringAttributes and not UIStringAttributes and couldn't figure it out. Be careful to not use this : new NSAttributedString("placeholderstring", new CTStringAttributes() { ForegroundColor = UIColor.Blue.CGColor });
8

iOS 6 and later offers attributedPlaceholder on UITextField. iOS 3.2 and later offers setAttributes:range: on NSMutableAttributedString.

You can do the following:

NSMutableAttributedString *ms = [[NSMutableAttributedString alloc] initWithString:self.yourInput.placeholder]; UIFont *placeholderFont = self.yourInput.font; NSRange fullRange = NSMakeRange(0, ms.length); NSDictionary *newProps = @{NSForegroundColorAttributeName:[UIColor yourColor], NSFontAttributeName:placeholderFont}; [ms setAttributes:newProps range:fullRange]; self.yourInput.attributedPlaceholder = ms; 

2 Comments

Not sure what is causing the problem, this code i have called in viewdidLoad. new color and font size appears only after redraw. any thing else needs to be done along with this?
it got solved, i forgot to set font for UITextfield before using that font for placeholder text. my bad
7

To handle both vertical and horizontal alignment as well as color of placeholder in iOS7. drawInRect and drawAtPoint no longer use current context fillColor.

https://developer.apple.com/library/ios/documentation/StringsTextFonts/Conceptual/TextAndWebiPhoneOS/CustomTextProcessing/CustomTextProcessing.html

Obj-C

@interface CustomPlaceHolderTextColorTextField : UITextField @end @implementation CustomPlaceHolderTextColorTextField : UITextField -(void) drawPlaceholderInRect:(CGRect)rect { if (self.placeholder) { // color of placeholder text UIColor *placeHolderTextColor = [UIColor redColor]; CGSize drawSize = [self.placeholder sizeWithAttributes:[NSDictionary dictionaryWithObject:self.font forKey:NSFontAttributeName]]; CGRect drawRect = rect; // verticially align text drawRect.origin.y = (rect.size.height - drawSize.height) * 0.5; // set alignment NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init]; paragraphStyle.alignment = self.textAlignment; // dictionary of attributes, font, paragraphstyle, and color NSDictionary *drawAttributes = @{NSFontAttributeName: self.font, NSParagraphStyleAttributeName : paragraphStyle, NSForegroundColorAttributeName : placeHolderTextColor}; // draw [self.placeholder drawInRect:drawRect withAttributes:drawAttributes]; } } @end 

1 Comment

Thanks for this excellent solution-- which properly centers text vertically (useful with custom fonts). The only thing I would add is that this solution is not compatible with iOS 6 or older (easy enough to fix by falling back on [self.placeholder drawInRect:rect withFont:self.font lineBreakMode:NSLineBreakByTruncatingTail alignment:self.textAlignment];
7

This solution for Swift 4.1

 textName.attributedPlaceholder = NSAttributedString(string: textName.placeholder!, attributes: [NSAttributedStringKey.foregroundColor : UIColor.red]) 

Comments

7

Swift 5 WITH CAVEAT.

let attributes = [ NSAttributedString.Key.foregroundColor: UIColor.someColor ] let placeHolderString = NSAttributedString(string: "DON'T_DELETE", attributes: attributes) txtField.attributedPlaceholder = placeHolderString 

The caveat being that you MUST enter a non-empty String where "DON'T_DELETE" is, even if that string is set in code elsewhere. Might save you five minutes of head-sctratching.

  • if subclassing you MUST do it in layoutSubviews (not in init)

  • strangely you do NOT have to clear the normal placeholder. it knows to not draw placeholder if you're using the attributed placeholder.

Comments

6

Categories FTW. Could be optimized to check for effective color change.


#import <UIKit/UIKit.h> @interface UITextField (OPConvenience) @property (strong, nonatomic) UIColor* placeholderColor; @end #import "UITextField+OPConvenience.h" @implementation UITextField (OPConvenience) - (void) setPlaceholderColor: (UIColor*) color { if (color) { NSMutableAttributedString* attrString = [self.attributedPlaceholder mutableCopy]; [attrString setAttributes: @{NSForegroundColorAttributeName: color} range: NSMakeRange(0, attrString.length)]; self.attributedPlaceholder = attrString; } } - (UIColor*) placeholderColor { return [self.attributedPlaceholder attribute: NSForegroundColorAttributeName atIndex: 0 effectiveRange: NULL]; } @end 

Comments

4

Overriding drawPlaceholderInRect: would be the correct way, but it does not work due to a bug in the API (or the documentation).

The method never gets called on an UITextField.

See also drawTextInRect on UITextField not called

You might use digdog's solution. As I am not sure if that gets past Apples review, I chose a different solution: Overlay the text field with my own label which imitates the placeholder behaviour.

This is a bit messy though. The code looks like this (Note I am doing this inside a subclass of TextField):

@implementation PlaceholderChangingTextField - (void) changePlaceholderColor:(UIColor*)color { // Need to place the overlay placeholder exactly above the original placeholder UILabel *overlayPlaceholderLabel = [[[UILabel alloc] initWithFrame:CGRectMake(self.frame.origin.x + 8, self.frame.origin.y + 4, self.frame.size.width - 16, self.frame.size.height - 8)] autorelease]; overlayPlaceholderLabel.backgroundColor = [UIColor whiteColor]; overlayPlaceholderLabel.opaque = YES; overlayPlaceholderLabel.text = self.placeholder; overlayPlaceholderLabel.textColor = color; overlayPlaceholderLabel.font = self.font; // Need to add it to the superview, as otherwise we cannot overlay the buildin text label. [self.superview addSubview:overlayPlaceholderLabel]; self.placeholder = nil; } 

3 Comments

how would you feel about sharing your review-friendly solution?
I added the solution I used. I had to do a bit of digging, as this was some time ago :)
I did something similar to this, but I placed the code in a category, and needed to do a check in shouldChangeCharacters on whether to make it visible, which was a second method in the category called - (void) overlayPlaceholderVisible : (BOOL) visible;
3

Iam new to xcode and i found a way around to the same effect.

I placed a uilabel in place of place holder with the desired format and hide it in

- (void)textFieldDidBeginEditing:(UITextField *)textField { switch (textField.tag) { case 0: lblUserName.hidden=YES; break; case 1: lblPassword.hidden=YES; break; default: break; } } 

I agree its a work around and not a real solution but the effect was same got it from this link

NOTE: Still works on iOS 7 :|

Comments

2

The best i can do for both iOS7 and less is:

- (CGRect)placeholderRectForBounds:(CGRect)bounds { return [self textRectForBounds:bounds]; } - (CGRect)editingRectForBounds:(CGRect)bounds { return [self textRectForBounds:bounds]; } - (CGRect)textRectForBounds:(CGRect)bounds { CGRect rect = CGRectInset(bounds, 0, 6); //TODO: can be improved by comparing font size versus bounds.size.height return rect; } - (void)drawPlaceholderInRect:(CGRect)rect { UIColor *color =RGBColor(65, 65, 65); if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"7.0")) { [self.placeholder drawInRect:rect withAttributes:@{NSFontAttributeName:self.font, UITextAttributeTextColor:color}]; } else { [color setFill]; [self.placeholder drawInRect:rect withFont:self.font]; } } 

Comments

2

For those using Monotouch (Xamarin.iOS), here's Adam's answer, translated to C#:

public class MyTextBox : UITextField { public override void DrawPlaceholder(RectangleF rect) { UIColor.FromWhiteAlpha(0.5f, 1f).SetFill(); new NSString(this.Placeholder).DrawString(rect, Font); } } 

1 Comment

Great. This was not really obvious, you probably saved me some time :) I did edit your solution though, since I think it's a better idea to use the font set in the Font property of the text field.
2

For set Attributed Textfield Placeholder with Multiple color ,

Just specify the Text ,

 //txtServiceText is your Textfield _txtServiceText.placeholder=@"Badal/ Shah"; NSMutableAttributedString *mutable = [[NSMutableAttributedString alloc] initWithString:_txtServiceText.placeholder]; [mutable addAttribute: NSForegroundColorAttributeName value:[UIColor whiteColor] range:[_txtServiceText.placeholder rangeOfString:@"Badal/"]]; //Replace it with your first color Text [mutable addAttribute: NSForegroundColorAttributeName value:[UIColor orangeColor] range:[_txtServiceText.placeholder rangeOfString:@"Shah"]]; // Replace it with your secondcolor string. _txtServiceText.attributedPlaceholder=mutable; 

Output :-

enter image description here

Comments

1

I needed to keep the placeholder alignment so adam's answer was not enough for me.

To solve this I used a small variation that I hope will help some of you too:

- (void) drawPlaceholderInRect:(CGRect)rect { //search field placeholder color UIColor* color = [UIColor whiteColor]; [color setFill]; [self.placeholder drawInRect:rect withFont:self.font lineBreakMode:UILineBreakModeTailTruncation alignment:self.textAlignment]; } 

1 Comment

UILineBreakModeTailTruncation is deprecated as of iOS 6.
1
[txt_field setValue:ColorFromHEX(@"#525252") forKeyPath:@"_placeholderLabel.textColor"]; 

1 Comment

A little hint on this is that you are accessing a private iVar (_placeholderLabel) and in the past Apple has been a little fincky about doing that. :)
1

In Swift 3

import UIKit let TEXTFIELD_BLUE = UIColor.blue let TEXTFIELD_GRAY = UIColor.gray class DBTextField: UITextField { /// Tetxfield Placeholder Color @IBInspectable var palceHolderColor: UIColor = TEXTFIELD_GRAY func setupTextField () { self.attributedPlaceholder = NSAttributedString(string:self.placeholder != nil ? self.placeholder! : "", attributes:[NSForegroundColorAttributeName: palceHolderColor]) } } class DBLocalizedTextField : UITextField { override func awakeFromNib() { super.awakeFromNib() self.placeholder = self.placeholder } } 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.