How to underline a UILabel in Swift? I searched the Objective-C ones but couldn't quite get them to work in Swift.
 
    
    - 23,815
- 10
- 63
- 101
 
    
    - 38,543
- 21
- 161
- 168
- 
                    7`NSAttributedString`? – Larme Jan 20 '15 at 19:17
- 
                    whats with the dislikes? there is an obvious confusion here with the attibutes looking like method calls in objc – Esqarrouth Jan 26 '15 at 15:18
- 
                    here You Can get the easy way https://stackoverflow.com/questions/28268060/adding-underline-attribute-to-partial-text-uilabel-in-storyboard/30750184#30750184 – Kapil B Jul 04 '17 at 07:48
- 
                    here are the easy way [https://stackoverflow.com/questions/28268060/adding-underline-attribute-to-partial-text-uilabel-in-storyboard/30750184#30750184][1] – Kapil B Jul 04 '17 at 07:49
- 
                    Better solution algorithm with better solution you can look my answer https://stackoverflow.com/questions/28053334/how-to-underline-a-uilabel-in-swift/65122584#65122584 – Ucdemir Dec 03 '20 at 08:53
16 Answers
You can do this using NSAttributedString
Example:
let underlineAttribute = [NSAttributedString.Key.underlineStyle: NSUnderlineStyle.thick.rawValue]
let underlineAttributedString = NSAttributedString(string: "StringWithUnderLine", attributes: underlineAttribute)
myLabel.attributedText = underlineAttributedString
EDIT
To have the same attributes for all texts of one UILabel, I suggest you to subclass UILabel and overriding text, like that:
Swift 5
Same as Swift 4.2 but: You should prefer the Swift initializer NSRange over the old NSMakeRange, you can shorten to .underlineStyle and linebreaks improve readibility for long method calls.
class UnderlinedLabel: UILabel {
override var text: String? {
    didSet {
        guard let text = text else { return }
        let textRange = NSRange(location: 0, length: text.count)
        let attributedText = NSMutableAttributedString(string: text)
        attributedText.addAttribute(.underlineStyle,
                                    value: NSUnderlineStyle.single.rawValue,
                                    range: textRange)
        // Add other attributes if needed
        self.attributedText = attributedText
        }
    }
}
Swift 4.2
class UnderlinedLabel: UILabel {
override var text: String? {
    didSet {
        guard let text = text else { return }
        let textRange = NSMakeRange(0, text.count)
        let attributedText = NSMutableAttributedString(string: text)
        attributedText.addAttribute(NSAttributedString.Key.underlineStyle , value: NSUnderlineStyle.single.rawValue, range: textRange)
        // Add other attributes if needed
        self.attributedText = attributedText
        }
    }
}
Swift 3.0
class UnderlinedLabel: UILabel {
    
    override var text: String? {
        didSet {
            guard let text = text else { return }
            let textRange = NSMakeRange(0, text.characters.count)
            let attributedText = NSMutableAttributedString(string: text)
            attributedText.addAttribute(NSUnderlineStyleAttributeName , value: NSUnderlineStyle.styleSingle.rawValue, range: textRange)
            // Add other attributes if needed
            self.attributedText = attributedText
        }
    }
}
And you put your text like this :
@IBOutlet weak var label: UnderlinedLabel!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        label.text = "StringWithUnderLine"
    }
OLD:
Swift (2.0 to 2.3):
class UnderlinedLabel: UILabel {
    
    override var text: String? {
        didSet {
            guard let text = text else { return }
            let textRange = NSMakeRange(0, text.characters.count)
            let attributedText = NSMutableAttributedString(string: text)
            attributedText.addAttribute(NSUnderlineStyleAttributeName, value:NSUnderlineStyle.StyleSingle.rawValue, range: textRange)
            // Add other attributes if needed
            
            self.attributedText = attributedText
        }
    }
}
Swift 1.2:
class UnderlinedLabel: UILabel {
    
    override var text: String! {
        didSet {
            let textRange = NSMakeRange(0, count(text))
            let attributedText = NSMutableAttributedString(string: text)
            attributedText.addAttribute(NSUnderlineStyleAttributeName, value:NSUnderlineStyle.StyleSingle.rawValue, range: textRange)
            // Add other attributes if needed
            
            self.attributedText = attributedText
        }
    }
}
 
    
    - 6,356
- 7
- 32
- 47
 
    
    - 6,464
- 6
- 33
- 40
- 
                    
- 
                    I've been wondering for a long time: why do we have to use rawValue otherwise it crashes? – Bruno Muniz Nov 04 '19 at 01:58
- 
                    You should pass `UTF16` count instead of the character count when creating your textRange `NSRange` – Leo Dabus Mar 16 '20 at 04:22
- 
                    I've changed this solution to add a underlline on initialize, this way we can use it easily with storyboards `required init?(coder: NSCoder) { super.init(coder: coder) self.addUnderline() // your code }` – João Serra Nov 11 '20 at 18:47
- 
                    Better solution algorithm with better solution you can look my answer https://stackoverflow.com/questions/28053334/how-to-underline-a-uilabel-in-swift/65122584#65122584 – Ucdemir Dec 03 '20 at 08:53
Swift 5 & 4.2 one liner:
label.attributedText = NSAttributedString(string: "Text", attributes:
    [.underlineStyle: NSUnderlineStyle.single.rawValue])
Swift 4 one liner:
label.attributedText = NSAttributedString(string: "Text", attributes:
    [.underlineStyle: NSUnderlineStyle.styleSingle.rawValue])
Swift 3 one liner:
label.attributedText = NSAttributedString(string: "Text", attributes:
      [NSUnderlineStyleAttributeName: NSUnderlineStyle.styleSingle.rawValue])
 
    
    - 23,815
- 10
- 63
- 101
- 
                    1NSUnderlineStyle.styleSingle.rawValue has been renamed to NSUnderlineStyle.single.rawValue in swift 4.2 – Skaal Jan 11 '19 at 11:23
- 
                    
- 
                    
Swift 5:
1- Create a String extension to get attributedText
extension String {
    var underLined: NSAttributedString {
        NSMutableAttributedString(string: self, attributes: [.underlineStyle: NSUnderlineStyle.single.rawValue])
    }
}
2- Use it
On buttons:
<#YourButton#>.setAttributedTitle(<#YourButtonTitle#>.underLined, for: .normal)
On Labels:
<#YourLabel#>.attributedText = <#YourLabelTitle#>.underLined
 
    
    - 2,308
- 17
- 26
If you are looking for a way to do this without inheritance:
Swift 5
extension UILabel {
    func underline() {
        if let textString = self.text {
          let attributedString = NSMutableAttributedString(string: textString)
            attributedString.addAttribute(NSAttributedString.Key.underlineStyle,
                                          value: NSUnderlineStyle.single.rawValue,
                                          range: NSRange(location: 0, length: attributedString.length))
          attributedText = attributedString
        }
    }
}
Swift 3/4
// in swift 4 - switch NSUnderlineStyleAttributeName with NSAttributedStringKey.underlineStyle
extension UILabel {
    func underline() {
        if let textString = self.text {
          let attributedString = NSMutableAttributedString(string: textString)
          attributedString.addAttribute(NSUnderlineStyleAttributeName, value: NSUnderlineStyle.styleSingle.rawValue, range: NSRange(location: 0, length: attributedString.length))
          attributedText = attributedString
        }
    }
}
extension UIButton {
  func underline() {
    let attributedString = NSMutableAttributedString(string: (self.titleLabel?.text!)!)
    attributedString.addAttribute(NSUnderlineStyleAttributeName, value: NSUnderlineStyle.styleSingle.rawValue, range: NSRange(location: 0, length: (self.titleLabel?.text!.characters.count)!))
    self.setAttributedTitle(attributedString, for: .normal)
  }
}
 
    
    - 23,770
- 8
- 136
- 129
 
    
    - 885
- 7
- 14
- 
                    You should pass `UTF16` count instead of the character count when creating your `NSRange` – Leo Dabus Mar 16 '20 at 04:27
Just a little fix for the Shlome answer in Swift 4 and Xcode 9.
extension UILabel {
    func underline() {
        if let textString = self.text {
            let attributedString = NSMutableAttributedString(string: textString)
            attributedString.addAttribute(NSAttributedStringKey.underlineStyle,
                                          value: NSUnderlineStyle.styleSingle.rawValue,
                                          range: NSRange(location: 0, length: attributedString.length - 1))
            attributedText = attributedString
        }
    }
}
    extension UIButton {
        func underline() {
            let attributedString = NSMutableAttributedString(string: (self.titleLabel?.text!)!)
            attributedString.addAttribute(NSAttributedStringKey.underlineStyle,
                                          value: NSUnderlineStyle.styleSingle.rawValue,
                                          range: NSRange(location: 0, length: (self.titleLabel?.text!.count)!))
            self.setAttributedTitle(attributedString, for: .normal)
        }
    }
 
    
    - 409
- 5
- 11
- 
                    You should pass `UTF16` count instead of the character count when creating your `NSRange` – Leo Dabus Mar 16 '20 at 04:28
You can underline the UILabel text using Interface Builder.   
Here is the link of my answer : Adding underline attribute to partial text UILabel in storyboard
 
    
    - 1
- 1
 
    
    - 2,824
- 2
- 27
- 49
Same Answer in Swift 4.2
For UILable
extension UILabel {
    func underline() {
        if let textString = self.text {
            let attributedString = NSMutableAttributedString(string: textString)
            attributedString.addAttribute(NSAttributedString.Key.underlineStyle,
                                          value: NSUnderlineStyle.single.rawValue,
                                          range: NSRange(location: 0, length: textString.count))
            self.attributedText = attributedString
        }
    }
}
Call for UILabel like below
myLable.underline()
For UIButton
extension UIButton {
    func underline() {
        if let textString = self.titleLabel?.text {
            let attributedString = NSMutableAttributedString(string: textString)
            attributedString.addAttribute(NSAttributedString.Key.underlineStyle,
                                          value: NSUnderlineStyle.single.rawValue,
                                          range: NSRange(location: 0, length: textString.count))
            self.setAttributedTitle(attributedString, for: .normal)
        }
    }
}
Call for UIButton like below
myButton.underline()
I looked into above answers and some of them are force unwrapping text value. I will suggest to get value by safely unwrapping. This will avoid crash in case of nil value. Hope This helps :)
 
    
    - 2,386
- 1
- 20
- 34
- 
                    
- 
                    You should pass `UTF16` count instead of the character count when creating your `NSRange` – Leo Dabus Mar 16 '20 at 04:28
- 
                    If you already have the extension for the UILabel, IMO it is simpler to call myButton.titleLabel?.underline(), or at least use it inside the underline() function in the extension for UIButton. – boherna Jun 09 '20 at 18:47
Swift 4, 4.2 and 5.
  @IBOutlet weak var lblUnderLine: UILabel!
I need to underline particular text in UILabel. So, find range and set attributes.
    let strSignup = "Don't have account? SIGNUP NOW."
    let rangeSignUp = NSString(string: strSignup).range(of: "SIGNUP NOW.", options: String.CompareOptions.caseInsensitive)
    let rangeFull = NSString(string: strSignup).range(of: strSignup, options: String.CompareOptions.caseInsensitive)
    let attrStr = NSMutableAttributedString.init(string:strSignup)
    attrStr.addAttributes([NSAttributedString.Key.foregroundColor : UIColor.white,
                           NSAttributedString.Key.font : UIFont.init(name: "Helvetica", size: 17)! as Any],range: rangeFull)
    attrStr.addAttributes([NSAttributedString.Key.foregroundColor : UIColor.white,
                           NSAttributedString.Key.font : UIFont.init(name: "Helvetica", size: 20)!,
                          NSAttributedString.Key.underlineStyle: NSUnderlineStyle.thick.rawValue as Any],range: rangeSignUp) // for swift 4 -> Change thick to styleThick
    lblUnderLine.attributedText = attrStr
Output
 
    
    - 9,221
- 1
- 66
- 58
Underline to multiple strings in a sentence.
extension UILabel {
    func underlineMyText(range1:String, range2:String) {
        if let textString = self.text {
            let str = NSString(string: textString)
            let firstRange = str.range(of: range1)
            let secRange = str.range(of: range2)
            let attributedString = NSMutableAttributedString(string: textString)
            attributedString.addAttribute(NSAttributedString.Key.underlineStyle, value: NSUnderlineStyle.single.rawValue, range: firstRange)
            attributedString.addAttribute(NSAttributedString.Key.underlineStyle, value: NSUnderlineStyle.single.rawValue, range: secRange)
            attributedText = attributedString
        }
    }
}
Use by this way.
    lbl.text = "By continuing you agree to our Terms of Service and Privacy Policy."
    lbl.underlineMyText(range1: "Terms of Service", range2: "Privacy Policy.")
 
    
    - 1,285
- 1
- 17
- 30
Swift 4 changes. Remeber to use NSUnderlineStyle.styleSingle.rawValue instead of NSUnderlineStyle.styleSingle.
   'let attributedString = NSAttributedString(string: "Testing")
    let textRange = NSMakeRange(0, attributedString.length)
    let underlinedMessage = NSMutableAttributedString(attributedString: attributedString)
    underlinedMessage.addAttribute(NSAttributedStringKey.underlineStyle,
                                   value:NSUnderlineStyle.styleSingle.rawValue,
                                   range: textRange)
    label.attributedText = underlinedMessage
`
 
    
    - 1,155
- 1
- 11
- 26
You can use this also if you want to achieve only half part of label as underline:- //For Swift 4.0+
let attributesForUnderLine: [NSAttributedString.Key: Any] = [
            .font: UIFont(name: AppFont.sourceSansPro_Regular, size: 12) ?? UIFont.systemFont(ofSize: 11),
            .foregroundColor: UIColor.blue,
            .underlineStyle: NSUnderlineStyle.single.rawValue]
        let attributesForNormalText: [NSAttributedString.Key: Any] = [
            .font: UIFont(name: AppFont.sourceSansPro_Regular, size: 12) ?? UIFont.systemFont(ofSize: 11),
            .foregroundColor: AppColors.ColorText_787878]
        let textToSet = "Want to change your preferences? Edit Now"
        let rangeOfUnderLine = (textToSet as NSString).range(of: "Edit Now")
        let rangeOfNormalText = (textToSet as NSString).range(of: "Want to change your preferences?")
        let attributedText = NSMutableAttributedString(string: textToSet)
        attributedText.addAttributes(attributesForUnderLine, range: rangeOfUnderLine)
        attributedText.addAttributes(attributesForNormalText, range: rangeOfNormalText)
        yourLabel.attributedText = attributedText
 
    
    - 893
- 9
- 19
The answer above is causing an error in my build environment.
This doesn't work in Swift 4.0:
attributedText.addAttribute(NSUnderlineStyleAttributeName, 
                            value: NSUnderlineStyle.styleSingle.rawValue, 
                            range: textRange)
Try this instead:
attributedText.addAttribute(NSAttributedStringKey.underlineStyle,
                            value: NSUnderlineStyle.styleSingle.rawValue,
                            range: textRange)
hope this helps someone.
// Swift 4 Version
 let attributedString  = NSMutableAttributedString(string: "Your Text Here", attributes: [NSAttributedStringKey.underlineStyle : true])
self.yourlabel.attributedText = attributedString
 
    
    - 4,745
- 1
- 42
- 57
 
    
    - 487
- 5
- 12
A class to set and remove underline for UIbuttons for Swift 5. I hope this helps
import Foundation
   import UIKit
   class UiUtil {
       static let underlineThickness = 2
    
       class func removeUnderlineFromButton( _ button:UIButton ) {
          if let str = button.titleLabel?.attributedText {
            let attributedString = NSMutableAttributedString( attributedString: str )
            attributedString.removeAttribute(.underlineStyle, range: 
   NSRange.init(location: 0, length: attributedString.length))
            button.setAttributedTitle(attributedString, for: .normal)
         }
      }
    class func setUnderlineFromButton( _ button:UIButton ) {
        if let str = button.titleLabel?.attributedText {
            let attributedStringUnderline = NSMutableAttributedString( attributedString: 
    str  )
              attributedStringUnderline.addAttribute(
                NSAttributedString.Key.underlineStyle,
                value: underlineThickness,
                range: NSRange.init(location: 0, length: attributedStringUnderline.length)
              )
              button.setAttributedTitle(attributedStringUnderline, for: .normal)
           }
      }
   }
 
    
    - 351
- 3
- 9
I have algorithm that used in my app. In this algorithm you can underline substring even that have space between words
extension NSMutableAttributedString{
    static func  findSubStringAndUnderlineIt(subStringToBeFound : String,totalString : String)->  NSMutableAttributedString?{
        
        let attributedString = NSMutableAttributedString(string: totalString)
        var spaceCount = 0
        
        if subStringToBeFound.contains(" "){
            spaceCount = subStringToBeFound.components(separatedBy:" ").count-1
        }
        
        if  let range = attributedString.string.range(of: subStringToBeFound, options: .caseInsensitive){
        
            attributedString.addAttribute(NSAttributedString.Key.underlineStyle, value: NSUnderlineStyle.single.rawValue, range: NSMakeRange((range.lowerBound.utf16Offset(in: subStringToBeFound)) ,(range.upperBound.utf16Offset(in: subStringToBeFound)) +
            spaceCount))
                return attributedString
        }
        return attributedString
        
    }
    
}
in used section
 lblWarning.attributedText = NSMutableAttributedString.findSubStringAndUnderlineIt(subStringToBeFound:"Not: Sadece uygulamanın reklamları kaldırılacaktır.", totalString: lblWarning.text!)
 
    
    - 2,852
- 2
- 26
- 44
For Swift 2.3
extension UIButton {
    func underline() {
        let attributedString = NSMutableAttributedString(string: (self.titleLabel?.text!)!)
        attributedString.addAttribute(NSUnderlineStyleAttributeName, value: NSUnderlineStyle.StyleSingle.rawValue, range: NSRange(location: 0, length: (self.titleLabel?.text!.characters.count)!))
        self.setAttributedTitle(attributedString, forState: .Normal)
    }
}
and in ViewController
@IBOutlet var yourButton: UIButton!
in ViewDidLoad Method or in your function just write 
yourButton.underline()
it will underline the title of your button
 
    
    - 4,745
- 1
- 42
- 57
 
    
    - 130
- 1
- 8

 
    