Ellipsis getting added in the toolbar text when font is set on attributed string

In my project, I am getting some text from backend which could have html tags. For this, I am converting the string to attributed string. However I noticed that when the string has html tags with color in it and when the text is displayed in toolbar, then the text displays with an ellipsis towards the end. Sharing code below:

import SwiftUI

struct ContentViewA: View {
    @State private var displayText: AttributedString?
    
    var body: some View {
        NavigationStack {
            VStack {
                Text(displayText ?? "")
            }
            .toolbar {
                ToolbarItem(placement: .cancellationAction) {
                    Button {
                    } label: {
                        Text("Done").font(.body.bold())
                    }
                }
                
                ToolbarItem(placement: .principal) {
                    Text(displayText ?? "")
                }
            }
            .onAppear {
                let string = "<div><p><span style=\"color:#FF0000;\">Hello World</span></p></div>"
                displayText = string.convertToAttributedString
                /// Note: If I don't set the font, then the ellipsis are not displayed in the toolbar, but I need this font style.
                displayText?.font = .body.bold()
            }
        }

    }
}

extension String {
    var convertToAttributedString: AttributedString? {
        guard let data = data(using: .utf8) else { return nil }
        var attributedString: AttributedString?
        if let nsAttributedString = try? NSAttributedString(data: data, options: [.documentType: NSAttributedString.DocumentType.html,
                                                                                  .characterEncoding: String.Encoding.utf8.rawValue],
                                                            documentAttributes: nil) {
            attributedString = try? AttributedString(nsAttributedString, including: \.uiKit)
        }
        
        return attributedString
    }
}

I am printing displayText in the body of the view and am not seeing ellipsis at the end of the string, but in toolbar, I am seeing ellipsis. I am unable to figure out what's causing this and what can be the fix for it. However, if I avoid setting the font on attributed string, then the ellipsis are not displayed in toolbar. However, I need to set the string to a specific font style.

How can I avoid ellipsis in toolbar and while also setting the required font on the string?

Answered by DTS Engineer in 828963022

I can't reproduce the ellipsis running with iOS 18.3.1 on an iPhone 16, but I was able to see that a CR is being added to the end of the string. This is most likely because of the <p> or the <div> tags.

note:

let string = "<div><p><span style=\"color:#FF0000;\">Hello World</span></p></div>"
displayText = string.convertToAttributedString
print("the text = '\(NSAttributedString(displayText!).string)'")

prints:

the text = 'Hello World
'

but

let string = "<span style=\"color:#FF0000;\">Hello World</span>"
displayText = string.convertToAttributedString
print("the text = '\(NSAttributedString(displayText!).string)'")

prints:

the text = 'Hello World'

Show us a screenshot of the issue.

Screen shot of the issue. Attributed string does not have ellipsis when displayed in the body of the view, but has ellipsis when displayed in the toolbar header.

One thing that I am noticing is if a string with html tags in it is converted to attributed string using the below block of code, then the attributed string has an additional newline character at the end of the string which is displayed as ellipsis in tool bar.

NSAttributedString(data: data, options: [.documentType: NSAttributedString.DocumentType.html,
                                                                           .characterEncoding: String.Encoding.utf8.rawValue]

Ah, yes, that's likely the issue. You can only put one line in the navigation bar title, so adding a newline character looks like it adds the ellipsis.

You'll need to trim the attributed string or replace all newlines with blank, so it's only one line?

I can't reproduce the ellipsis running with iOS 18.3.1 on an iPhone 16, but I was able to see that a CR is being added to the end of the string. This is most likely because of the <p> or the <div> tags.

note:

let string = "<div><p><span style=\"color:#FF0000;\">Hello World</span></p></div>"
displayText = string.convertToAttributedString
print("the text = '\(NSAttributedString(displayText!).string)'")

prints:

the text = 'Hello World
'

but

let string = "<span style=\"color:#FF0000;\">Hello World</span>"
displayText = string.convertToAttributedString
print("the text = '\(NSAttributedString(displayText!).string)'")

prints:

the text = 'Hello World'

I am able to reproduce the issue even with other html tags.

Eg: let string = "<h1>Hello World</h1>"

I was working with iOS 17 and I was trying to print attributed string directly i.e.

print(displayText) 

and not

print("the text = '\(NSAttributedString(displayText!).string)'")

Also in case of the app I am working on, HTML string would be coming from the end user, so I don't have control over the tags so the string could have "<div><p>" tags in it.

I will try playing around with more HTML tags and using NSAttributedString(displayText!).string instead of displayText to see if it changes anything.

Interesting observation. I would kind of expect that sort of thing with an H1 tag. It's for a header. In html if you add a H1 tag, it'll usually be terminated with a line break just like a P tag or a DIV tag.

For example, take the HTML:

<H1>header</H1><P>paragraph text</P><P>more <B>paragraph</B> text</P>

without any css, it'll be displayed something like so in most browsers:

header

paragraph text

more paragraph text

NOTE: I didn't put any line breaks in the HTML, but a browser would normally render the html with the line breaks as shown above. Also note, the <B> tag (bold) is an inline tag so it isn't taken out of the flow with line breaks.

Of course there are no rules that I'm aware of for converting HTML tags to AttributedStrings but if I were trying to do so in a way that allows the formatting of the AttributeString to reasonably mimic the formatting provided by most browsers, I'd add a line break after the block structured tags like the heading tags (H1, H2, H3, ...), P, DIV, and others. And I would not add line breaks around the inline tags like SPAN, B, I, and others.

Ellipsis getting added in the toolbar text when font is set on attributed string
 
 
Q