HTML
NSAttributedText
font styling
iOS development
text parsing

Parsing HTML into NSAttributedText - how to set font?

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

When you convert HTML into NSAttributedString, the HTML importer often brings along its own font choices. That is why simply setting a font on the label afterward does not always produce the result you want. The reliable solution is to parse the HTML into an attributed string first, then walk the attributed ranges and replace the imported fonts with your preferred font family while preserving traits such as bold and italic.

Parse The HTML First

Start by converting HTML data into an attributed string.

swift
1import UIKit
2
3func attributedString(from html: String) throws -> NSMutableAttributedString {
4    let data = Data(html.utf8)
5    let options: [NSAttributedString.DocumentReadingOptionKey: Any] = [
6        .documentType: NSAttributedString.DocumentType.html,
7        .characterEncoding: String.Encoding.utf8.rawValue
8    ]
9
10    let attributed = try NSMutableAttributedString(
11        data: data,
12        options: options,
13        documentAttributes: nil
14    )
15
16    return attributed
17}

This gives you a mutable attributed string containing whatever fonts the HTML parser inferred.

Why Setting label.font Is Not Enough

If a UILabel or UITextView receives an attributed string, the font attributes inside that attributed string usually take priority over the plain font property of the view.

So this often disappoints people:

swift
label.attributedText = try? attributedString(from: html)
label.font = UIFont.systemFont(ofSize: 16)

The imported HTML fonts still win because the attributed text already contains font attributes.

Replace Imported Fonts While Preserving Traits

The practical fix is to enumerate .font attributes and swap each one for a version of your target font family with matching symbolic traits.

swift
1import UIKit
2
3func applyingFont(_ baseFont: UIFont, to attributed: NSMutableAttributedString) {
4    let fullRange = NSRange(location: 0, length: attributed.length)
5
6    attributed.enumerateAttribute(.font, in: fullRange) { value, range, _ in
7        let currentFont = value as? UIFont ?? baseFont
8        let traits = currentFont.fontDescriptor.symbolicTraits
9
10        var descriptor = baseFont.fontDescriptor
11        if let withTraits = descriptor.withSymbolicTraits(traits) {
12            descriptor = withTraits
13        }
14
15        let replacement = UIFont(descriptor: descriptor, size: baseFont.pointSize)
16        attributed.removeAttribute(.font, range: range)
17        attributed.addAttribute(.font, value: replacement, range: range)
18    }
19}

Usage:

swift
1let html = "<b>Hello</b> <i>world</i>"
2let attributed = try attributedString(from: html)
3applyingFont(UIFont.systemFont(ofSize: 16), to: attributed)
4label.attributedText = attributed

Now the output uses your preferred family and size while still respecting bold and italic where possible.

A Complete Helper

swift
1import UIKit
2
3func htmlToAttributedString(html: String, font: UIFont) -> NSAttributedString? {
4    do {
5        let attributed = try attributedString(from: html)
6        applyingFont(font, to: attributed)
7        return attributed
8    } catch {
9        print("HTML parse error: \(error)")
10        return nil
11    }
12}

This is a good reusable utility for labels and text views.

CSS In The HTML Is Another Option

You can also inject a CSS style block into the HTML itself so the importer starts closer to your desired font.

swift
1let html = """
2<style>
3body {
4  font-family: -apple-system;
5  font-size: 16px;
6}
7</style>
8<p><b>Hello</b> world</p>
9"""

This can help, but it is not always enough on its own, especially when imported HTML includes nested tags with their own styling. Post-processing the attributed string is usually more reliable.

Preserve More Than Just Font Family

If your design requires custom line spacing, color, or paragraph style, handle those attributes separately. Font replacement solves the typography family problem, but it does not automatically normalize every other imported HTML attribute.

That is another reason a dedicated post-processing helper is useful.

Common Pitfalls

  • Setting label.font and expecting it to override fonts already embedded in the attributed string.
  • Replacing fonts without preserving bold and italic traits.
  • Assuming the HTML importer will use your app's preferred font automatically.
  • Injecting CSS only and skipping attributed-string cleanup when the imported result is inconsistent.
  • Forgetting that NSAttributedText in the question is really NSAttributedString in the Apple APIs.

Summary

  • Parse HTML into an attributed string first, then adjust the font attributes inside it.
  • View-level font settings usually do not override fonts already stored in attributed text.
  • Enumerate .font attributes and replace them with your preferred font family.
  • Preserve symbolic traits so bold and italic styling still works.
  • CSS can help, but post-processing the attributed string is usually the most reliable fix.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.