NSTextAttachment is a class from the UIKit framework that allows embedding images and other media objects into formatted text through NSAttributedString. It works at the TextKit and Core Text level, giving developers control over the size, position, and behavior of attachments within the text flow. According to Apple Documentation (2025), NSTextAttachment supports images, PDF, and custom view containers, integrating with UITextView and UILabel. Understanding this API is necessary for creating Rich Text in iOS applications — from chats and editors to news feeds with icons in captions.
Key Takeaways
NSTextAttachment is a class from the UIKit framework that allows embedding media objects directly into the text content of NSAttributedString. Unlike a separate UIImageView placed next to text, NSTextAttachment makes the image part of the text flow: the image wraps with lines, participates in alignment, and takes up space like a regular character.
The class is part of the TextKit architecture, which manages text rendering on iOS and macOS. TextKit breaks text into glyphs, takes into account kerning, ligatures, and leading — and NSTextAttachment fits into this pipeline as a special character that renders not as a letter but as a graphic object.
Each NSTextAttachment instance contains contents (file data), fileType (UTI content type), and bounds (a rectangle in points defining size and position). According to Apple Human Interface Guidelines, bounds default to the image size but can be changed for precise fit with the font.
Use NSTextAttachment instead of a separate UIImageView when the image should behave as part of the text — in chats, news feeds, text editors, and forms with icons in input fields.
The basic workflow with NSTextAttachment consists of three steps: create an instance, set the image, and attach it to NSAttributedString. Let’s look at the process using Swift.
let attachment = NSTextAttachment()
attachment.image = UIImage(named: "icon-star")
let attachmentString = NSAttributedString(attachment: attachment)
let text = NSMutableAttributedString(string: "Rating: ")
text.append(attachmentString)
let label = UILabel()
label.attributedText = text
After calling NSAttributedString(attachment:), the NSTextAttachment object is converted to the NSAttachmentAttributeName attribute, which is attached to a special object replacement character (code 0xFFFC). This character is not displayed as a letter — instead, the image from the image property is drawn in its place.
If the image should be placed in the middle of a text line (for example, an icon after a word), simply insert the attachmentString at the desired position in NSMutableAttributedString. TextKit will automatically account for the line height and align the image to the baseline.
Important: the image property is only available on iOS (since iOS 7). On macOS, use the contents property with NSImage. For backward compatibility, always prefer setting image directly rather than relying on the data container.
By default, NSTextAttachment displays the image at its original size in points. In practice, you almost always need to adjust the size and vertical position — this is done using the bounds property.
The CGRect bounds structure includes origin (offset by X and Y) and size (width and height). The Y offset is particularly important: a negative value lowers the image below the baseline, a positive value raises it. A typical scenario is to align an icon to the center of a text line.
let attachment = NSTextAttachment()
attachment.image = UIImage(named: "icon-star")
let font = UIFont.systemFont(ofSize: 16)
let fontCapHeight = font.capHeight
let imageSize = CGSize(width: 18, height: 18)
attachment.bounds = CGRect(
x: 0,
y: (fontCapHeight - imageSize.height) / 2,
width: imageSize.width,
height: imageSize.height
)
The alignment calculation uses the font’s capHeight — the height of a capital letter, not the full line height. This ensures the icon visually matches the top edge of the text rather than floating between the baseline and ascender. The image size in the example is 18×18 pt, which is typical for icons in UI text.
If the image should be larger than the text line (for example, a photo preview in a chat), TextKit will automatically increase the line spacing for the current line. In this case, bounds should be set to the natural size, and the Y offset to zero.
NSTextAttachment supports not only PNG and JPEG but also PDF documents, as well as arbitrary files through the contents property. This makes it a universal tool for Rich Text in iOS applications.
When setting a PDF image to attachment.image, the system automatically renders the first page of the document. However, for precise rendering, use the data directly through the initializer with data and UTI type:
guard let pdfData = Bundle.main.url(forResource: "document",
withExtension: "pdf") else { return }
let fileData = Data(contentsOf: pdfData)
let attachment = NSTextAttachment(data: fileData,
ofType: "com.adobe.pdf")
attachment.bounds = CGRect(x: 0, y: -4,
width: 24, height: 24)
let pdfString = NSAttributedString(attachment: attachment)
The ofType parameter accepts a UTI string (Uniform Type Identifier). Standard types include: public.image (any image), public.jpeg, public.png, com.adobe.pdf. When specifying the correct UTI, the system selects the appropriate rendering method — for PDF it’s CGPDFDocument, for images it’s CGImageSource.
For custom file types (for example, vector graphics in SVG format), you will need an NSTextAttachment subclass that overrides the image(forBounds:textContainer:characterIndex:) method. If the standard rendering is not suitable, return nil and implement drawing via Core Graphics in the draw method.
NSTextAttachment works correctly in both UILabel and UITextView. However, UITextView provides more capabilities: interaction with attachments (tapping on an icon), editing text along with images, and support for NSAttachmentBehavior.
To handle taps on NSTextAttachment in UITextView, use the UITextViewDelegate protocol and the textView(_:shouldInteractWith:in:interaction:) method. This method is called when the user taps an attachment and allows navigating to a screen, opening a popup, or playing an animation.
func textView(_ textView: UITextView,
shouldInteractWith attachment: NSTextAttachment,
in characterRange: NSRange,
interaction: UITextItemInteraction) -> Bool {
if interaction == .preview {
return false
}
// Open detail screen
showImageDetail(attachment.image)
return false
}
The method distinguishes interaction types through the interaction parameter: .preview (3D Touch / Haptic Touch), .default (regular tap), and .presentActions (context menu). For each type, you can define its own behavior or disable it by returning false.
When editing UITextView with NSTextAttachment, it is important to remember: deleting the replacement character (0xFFFC) also deletes the attachment. The user sees the image as a single element — it is selected as a whole, not pixel by pixel. For drag-and-drop support of attachments on iOS 15+, use NSTextAttachmentViewProvider.
The first common mistake is ignoring bounds. Developers often rely on the original image size, which leads to giant icons in text or, conversely, images that are barely visible. Always set bounds explicitly taking into account the font and context.
The second mistake is incorrect Y offset. A positive value in bounds.origin.y lowers the image (in UIKit’s coordinate system, the Y axis points downward — this seems counterintuitive, but this is how Core Graphics works). To center-align within a line, use the formula with the font’s capHeight as shown in Section 3.
The third problem is image loss on traitCollection change. When the user switches Dark Mode or Dynamic Type, the font size may change, but bounds remain the same. The solution is to compute bounds dynamically in the layoutSubviews method or via KVO on font.
The fourth frequent mistake is using NSTextAttachment in UILabel with numberOfLines > 1. In multiline mode with limited width, TextKit correctly wraps lines together with the image. The problem arises when the attachment height exceeds the line height — adjacent lines overlap each other. The solution is to increase lineSpacing via NSMutableParagraphStyle.
Frequently Asked Questions
NSTextAttachment makes the image part of the text flow: it wraps, aligns, and scales with the text. UIImageView is bound to superview coordinates and does not participate in text layout.
Yes, if you set the attributedText property instead of text. UILabel correctly displays NSTextAttachment but does not support interactivity. For taps on the attachment, use UITextView.
Change the bounds property of the existing NSTextAttachment instance. The text will automatically re-render with the new sizes without needing to create a new NSAttributedString.
NSTextAttachment supports static images. For GIF and animated formats, a custom implementation via NSTextAttachmentViewProvider on iOS 15+ or via CADisplayLink is required.
Create an NSTextAttachment instance, set the image or data, set bounds, wrap it in NSAttributedString(attachment:), and insert it into NSMutableAttributedString using the insert(_:at:) method.
Summary
We will develop a mobile application turnkey
IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.
Read also