UILabel
strikethrough text
iOS development
Swift programming
UI design

How can I create a UILabel with strikethrough text?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

UILabel does not expose a direct "strikethrough" property. The standard way to draw a strike line is to assign an attributed string to attributedText and include the right text attributes for the range you want to style.

Once you think in terms of attributed text instead of plain text, the problem becomes straightforward. You can strike the whole label, only one substring, or rebuild the styling dynamically from model state.

Apply Strikethrough to the Entire Label

For the simplest case, create an NSAttributedString with .strikethroughStyle and assign it to the label:

swift
1import UIKit
2
3let label = UILabel()
4label.numberOfLines = 1
5
6let text = "Old price: $49.99"
7let attributes: [NSAttributedString.Key: Any] = [
8    .strikethroughStyle: NSUnderlineStyle.single.rawValue
9]
10
11label.attributedText = NSAttributedString(
12    string: text,
13    attributes: attributes
14)

This tells UIKit to render the label with a single strike line across the full text. The value comes from NSUnderlineStyle, even though the visual result is a strikethrough.

Style the Strike and the Text Together

Most real interfaces do more than just add a line. You usually want the struck text to look secondary, for example with a lighter color or a smaller font. These are just more attributes on the same string:

swift
1import UIKit
2
3let label = UILabel()
4
5let attributes: [NSAttributedString.Key: Any] = [
6    .font: UIFont.systemFont(ofSize: 16, weight: .medium),
7    .foregroundColor: UIColor.secondaryLabel,
8    .strikethroughStyle: NSUnderlineStyle.single.rawValue,
9    .strikethroughColor: UIColor.systemRed
10]
11
12label.attributedText = NSAttributedString(
13    string: "Old price: $49.99",
14    attributes: attributes
15)

This approach is flexible because the strike line and the text color are controlled independently. That is useful for sale prices, disabled states, completed tasks, and archived items.

Strike Only Part of the Label

Many interfaces need mixed styling. A shopping screen may show the old price struck through but the new price highlighted. Use NSMutableAttributedString so you can assign attributes to specific ranges:

swift
1import UIKit
2
3let label = UILabel()
4let fullText = "Was $49.99  Now $29.99"
5let attributed = NSMutableAttributedString(string: fullText)
6
7let oldRange = (fullText as NSString).range(of: "Was $49.99")
8attributed.addAttributes([
9    .foregroundColor: UIColor.secondaryLabel,
10    .strikethroughStyle: NSUnderlineStyle.single.rawValue
11], range: oldRange)
12
13let newRange = (fullText as NSString).range(of: "Now $29.99")
14attributed.addAttributes([
15    .foregroundColor: UIColor.systemGreen,
16    .font: UIFont.boldSystemFont(ofSize: 17)
17], range: newRange)
18
19label.attributedText = attributed

This is the pattern you want whenever different parts of the string carry different meaning.

Build a Reusable Helper

If your app applies this effect in several places, wrap the styling in a helper so view code stays clean:

swift
1import UIKit
2
3func makeStrikethroughText(
4    _ text: String,
5    color: UIColor = .secondaryLabel
6) -> NSAttributedString {
7    NSAttributedString(
8        string: text,
9        attributes: [
10            .foregroundColor: color,
11            .strikethroughStyle: NSUnderlineStyle.single.rawValue
12        ]
13    )
14}
15
16let label = UILabel()
17label.attributedText = makeStrikethroughText("Completed task")

For dynamic interfaces, it is often better to rebuild the attributed string from state than to try to mutate an existing one in place.

Update the Label From Model State

A common example is a to-do list where completed items should be crossed out:

swift
1import UIKit
2
3func configure(label: UILabel, title: String, isCompleted: Bool) {
4    if isCompleted {
5        label.attributedText = NSAttributedString(
6            string: title,
7            attributes: [
8                .strikethroughStyle: NSUnderlineStyle.single.rawValue,
9                .foregroundColor: UIColor.secondaryLabel
10            ]
11        )
12    } else {
13        label.attributedText = nil
14        label.text = title
15    }
16}

This is simple, readable, and safe for reusable cells in table views or collection views.

Common Pitfalls

The most common mistake is setting label.text after label.attributedText. Plain text assignment replaces the attributed value, so the strike line disappears.

Another common issue is using an invalid NSRange when styling only part of a string. If the substring is not found or the range is calculated incorrectly, the label may show partial formatting or crash in debug builds.

People also set .strikethroughColor without .strikethroughStyle. The color attribute alone is not enough. UIKit needs a style value before it draws the line.

Finally, reusable cells need full reconfiguration. If one cell shows struck text and the next one should not, reset both attributedText and text intentionally instead of assuming old state will disappear on its own.

Summary

  • Use attributedText, not text, to create strikethrough text in a UILabel.
  • Apply .strikethroughStyle to the whole string or to a specific range.
  • Combine the strike line with font and color attributes for realistic UI styling.
  • Use NSMutableAttributedString when only part of the label should be crossed out.
  • Reset reused labels carefully so old attributed state does not leak into new content.

Course illustration
Course illustration

All Rights Reserved.