UIButton
iOS Development
Swift Programming
Image Labeling
User Interface Design

Label under image in UIButton

Interview Questions practice on Codemia

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

Browse interview questions

Introduction

Putting a label under an image in a UIButton is a common iOS pattern for menus, tab-like launchers, and icon grids. UIKit does not place the image above the title by default, so you have to choose a layout approach that fits your deployment target.

If you support iOS 15 or later, UIButton.Configuration is the cleanest solution because it has built-in vertical image placement. On older versions, you can still get the same result with a small subclass or carefully calculated edge insets.

Use UIButton.Configuration on Modern iOS

For current UIKit code, prefer the configuration API. It directly supports top image placement and title spacing.

swift
1import UIKit
2
3var config = UIButton.Configuration.plain()
4config.title = "Photos"
5config.image = UIImage(systemName: "photo")
6config.imagePlacement = .top
7config.imagePadding = 8
8
9let button = UIButton(configuration: config)
10button.titleLabel?.textAlignment = .center

This is the best starting point because the button owns its own layout. You do not need manual geometry math, and the result behaves better with different font sizes and button widths.

If the title can wrap, add:

swift
button.titleLabel?.numberOfLines = 2
button.titleLabel?.adjustsFontSizeToFitWidth = true

That makes the design more resilient when localization or accessibility text sizes increase the title length.

Legacy UIKit Needs Manual Layout

Before UIButton.Configuration, vertical image-title layout usually meant adjusting insets after the button had measured its image and title. A small subclass keeps that logic in one place:

swift
1import UIKit
2
3final class VerticalButton: UIButton {
4    private let spacing: CGFloat = 8
5
6    override func layoutSubviews() {
7        super.layoutSubviews()
8
9        guard let imageView = imageView, let titleLabel = titleLabel else { return }
10
11        let imageSize = imageView.frame.size
12        let titleSize = titleLabel.intrinsicContentSize
13        let totalHeight = imageSize.height + spacing + titleSize.height
14
15        imageEdgeInsets = UIEdgeInsets(
16            top: -(totalHeight - imageSize.height),
17            left: 0,
18            bottom: 0,
19            right: -titleSize.width
20        )
21
22        titleEdgeInsets = UIEdgeInsets(
23            top: 0,
24            left: -imageSize.width,
25            bottom: -(totalHeight - titleSize.height),
26            right: 0
27        )
28
29        contentEdgeInsets = UIEdgeInsets(
30            top: spacing,
31            left: 8,
32            bottom: titleSize.height,
33            right: 8
34        )
35    }
36}

The important detail is layoutSubviews. That method runs after UIKit knows the sizes of the internal image view and title label. If you compute those insets too early, the values will be wrong.

Know When a Custom Control Is Better

Sometimes a button with an internal label and image is still too restrictive. If your design needs badges, subtitles, or more than one text line with custom spacing, a UIStackView inside a custom UIControl may be easier to maintain than pushing UIButton further than it wants to go.

That does not mean UIButton is wrong. It just means the right tool depends on how much state handling and layout freedom you need. For a simple icon-over-label design, the modern button configuration API is usually enough.

Test With Real Content

This layout often looks correct with a short English word and then breaks immediately with production content. Test these cases early:

  • long localized titles
  • larger dynamic type sizes
  • different image aspect ratios
  • constrained button widths in smaller devices

A vertical button needs enough height for both the image and the text. If Auto Layout compresses the control too much, the title will clip or overlap even when the layout code is correct.

Common Pitfalls

  • Calculating title and image positions before layout has established their sizes.
  • Using hard-coded inset values that only work for one title length or one icon size.
  • Forgetting content insets, which causes the title to press against the button edges.
  • Ignoring multiline or accessibility text sizes while testing only with short placeholder content.
  • Reimplementing complex manual layout on iOS 15 and later when UIButton.Configuration already solves the common case.

Summary

  • On iOS 15 and later, use UIButton.Configuration with imagePlacement = .top.
  • On older versions, a small subclass with inset math is the usual fallback.
  • Perform manual layout after UIKit knows the image and title sizes.
  • Test with real text lengths and dynamic type, not just ideal sample content.
  • If the design becomes too custom, consider a custom UIControl instead of forcing everything through UIButton.

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.