iOS
UILabel
NSTextAttachment
Swift
UI Design

Center NSTextAttachment image next to single line UILabel

Master System Design with Codemia

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

Introduction

When you place an image in a UILabel with NSTextAttachment, the image often looks slightly too high or too low because attachments align to the text baseline by default, not to the visual center of the line. For a single-line label, the usual fix is to set the attachment bounds with a vertical offset derived from the label font metrics, then build the attributed string once and assign it to the label.

Why the image looks off-center

A UILabel lays out text relative to a baseline, and NSTextAttachment participates in that same text layout. If you just drop in an image at its raw size, UIKit does not automatically center it against the visible text height.

That is why a small icon next to text often appears slightly low compared with the letters, even though the code is technically correct.

Build the attachment with a font-aware vertical offset

For single-line labels, a good approach is to size the image to the font's line height and then shift it vertically using the font's descender or cap height.

swift
1import UIKit
2
3func makeLabelText(text: String, image: UIImage, font: UIFont) -> NSAttributedString {
4    let attachment = NSTextAttachment()
5    attachment.image = image
6
7    let imageHeight = font.lineHeight
8    let ratio = image.size.width / image.size.height
9    let imageWidth = imageHeight * ratio
10
11    let yOffset = (font.capHeight - imageHeight) / 2
12    attachment.bounds = CGRect(x: 0, y: yOffset, width: imageWidth, height: imageHeight)
13
14    let result = NSMutableAttributedString(attachment: attachment)
15    result.append(NSAttributedString(string: " "))
16    result.append(NSAttributedString(string: text, attributes: [.font: font]))
17    return result
18}

Then apply it to the label.

swift
1let label = UILabel()
2label.font = .systemFont(ofSize: 17)
3label.numberOfLines = 1
4label.attributedText = makeLabelText(
5    text: "Verified",
6    image: UIImage(systemName: "checkmark.seal.fill")!,
7    font: label.font
8)

This gives you much more reliable visual alignment than the default attachment placement.

Choose the right metric for the offset

The exact offset formula is not universal because different fonts and icons have different visual centers. Two metrics are commonly useful:

  • 'font.capHeight when you want the icon to align with uppercase letter height'
  • 'font.descender when you want to compensate for how the baseline sits in the line box'

If the first formula still looks slightly off with your font and image, adjust the y offset by a point or two. This is normal UI tuning, not a sign that the whole method is wrong.

Keep the label single-line if that is the design

This technique is most predictable on single-line labels. Once the label wraps, line fragment geometry becomes more complex and an inline attachment may not produce the visual result you want.

If the label must support multiple lines with rich inline icons, consider whether a UIStackView with an UIImageView and UILabel would be a more controllable layout.

Match image size to the text, not to the asset file

Using the original pixel dimensions of the source image is rarely correct. The icon should normally be sized relative to the font, not relative to the asset.

That is why the example above derives imageHeight from font.lineHeight. It keeps the inline icon visually proportional to the text.

Recompute on font changes

If the label font changes because of Dynamic Type, theme changes, or configuration updates, recompute the attributed string. The previous attachment bounds were tuned for the old font metrics.

That is easy to forget in reusable cells or state-driven UI updates. A once-correct alignment can become wrong after the font changes.

Common Pitfalls

  • Inserting the attachment without adjusting its bounds and expecting automatic vertical centering.
  • Sizing the image from the raw asset dimensions instead of the label font metrics.
  • Using one hard-coded offset for every font and icon combination.
  • Applying the single-line attachment technique to a label that really needs a more flexible multi-view layout.
  • Forgetting to rebuild the attributed string when the label font changes.

Summary

  • 'NSTextAttachment aligns to the text baseline, not automatically to the visual center.'
  • For a single-line UILabel, center the icon by setting attachment bounds with a font-aware vertical offset.
  • Size the icon relative to the label font, usually around the line height.
  • Expect small per-font tuning rather than one universal perfect offset.
  • If the layout becomes multi-line or more complex, consider separate views instead of inline attachment text.

Course illustration
Course illustration

All Rights Reserved.