Swift
NSMutableAttributedString
iOS Development
Text Formatting
Swift Programming

Changing specific text's color using NSMutableAttributedString in Swift

Master System Design with Codemia

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

Introduction

If you want only part of a string to appear in a different color in UIKit, NSMutableAttributedString is the standard tool. The basic pattern is to create the full attributed string, locate the range of the target substring, and apply a .foregroundColor attribute to that range only.

The basic pattern

Start with the full text, then apply a base style to the entire range, and finally override the color for the part you want to highlight.

swift
1import UIKit
2
3let text = "Status: Active"
4let attributed = NSMutableAttributedString(string: text)
5
6attributed.addAttributes([
7    .font: UIFont.systemFont(ofSize: 16),
8    .foregroundColor: UIColor.label
9], range: NSRange(location: 0, length: (text as NSString).length))
10
11let targetRange = (text as NSString).range(of: "Active")
12attributed.addAttribute(.foregroundColor, value: UIColor.systemGreen, range: targetRange)
13
14label.attributedText = attributed

That is the common solution for status labels, prices, warnings, and mixed-emphasis text.

Why NSString bridging is useful

UIKit text APIs use NSRange, which is based on Objective-C string indexing rules. Swift String uses a different index model. That is why many developers bridge to NSString when building attributed ranges.

swift
let fullText = "Total due: $42"
let nsText = fullText as NSString
let range = nsText.range(of: "$42")

This keeps your range calculations aligned with the attributed string APIs.

Guard against missing substrings

If the target text is dynamic, always validate the range before applying attributes.

swift
1let text = "Hello world"
2let nsText = text as NSString
3let range = nsText.range(of: "Swift")
4
5if range.location != NSNotFound {
6    attributed.addAttribute(.foregroundColor, value: UIColor.systemBlue, range: range)
7}

Without that guard, you can crash by trying to style an invalid range.

Styling multiple parts differently

You can apply attributes in sequence for multiple substrings.

swift
1let message = "High Priority - Needs Review"
2let attributed = NSMutableAttributedString(string: message)
3let nsMessage = message as NSString
4
5attributed.addAttribute(.foregroundColor, value: UIColor.label,
6                        range: NSRange(location: 0, length: nsMessage.length))
7
8let highRange = nsMessage.range(of: "High Priority")
9let reviewRange = nsMessage.range(of: "Needs Review")
10
11if highRange.location != NSNotFound {
12    attributed.addAttribute(.foregroundColor, value: UIColor.systemRed, range: highRange)
13}
14
15if reviewRange.location != NSNotFound {
16    attributed.addAttribute(.foregroundColor, value: UIColor.systemOrange, range: reviewRange)
17}

This is more maintainable than trying to split the label into several separate UI elements.

Attribute combinations

Color is only one attribute. In practice, attributed strings are often used to combine:

That is why it usually pays to think of the string in layers: one base style for everything, then targeted overrides for the important fragments. This keeps formatting logic predictable as the text evolves.

  • color
  • font weight
  • underline
  • kerning
  • paragraph style

That means it is often worth applying a base style first so the highlighted segment changes only what it actually needs to change.

Repeated substrings need extra care

If the same word appears more than once, range(of:) finds only the first occurrence by default. If you need to style multiple matches, you must search iteratively or use a different range-selection strategy.

This matters in real text-processing code more than in short demo examples.

Common Pitfalls

A common mistake is mixing Swift string indexing assumptions with NSRange-based UIKit APIs.

Another mistake is applying an attribute to a substring that does not exist, which leads to an invalid range.

A third mistake is forgetting that range(of:) usually finds only the first match, not every occurrence.

Summary

  • Use NSMutableAttributedString to style specific parts of text.
  • Bridge to NSString when calculating NSRange values for UIKit APIs.
  • Apply a base style first, then override the target range.
  • Validate ranges before applying attributes to dynamic text.
  • Handle repeated substrings explicitly if more than one match should be styled.
  • Bridge carefully between Swift strings and NSRange-based UIKit APIs.

Course illustration
Course illustration

All Rights Reserved.