Icon Button Label

Status: ready

Intent

An icon button has a task name that the user can hear, say and understand.

Problem

An icon isn't a name. An asset name isn't user language. An SF Symbol name isn't product copy. A button called xmark isn't a button called "Close".

Solution

Verdict: visible text when there's room. Otherwise a localized accessibilityLabel that names the action or the destination, not the shape. When the icon repeats, the label names the object.

Why: the label is what VoiceOver reads, what Voice Control matches and what support says on the phone. A shape name helps none of them.

Good Bad
Close X icon
Share receipt square and arrow up
Filter results filterButton
Add jasmine tea to favorites Favorite (×10 in a list)

Implementation

SwiftUI, icon only:

Button {
    openFilters()
} label: {
    Image(systemName: "slider.horizontal.3")
}
.accessibilityLabel("Filter results")

SwiftUI, visible text. The visible text is the name, no extra label:

Button {
    openFilters()
} label: {
    Label("Filter results", systemImage: "slider.horizontal.3")
}

Label with .labelStyle(.iconOnly) keeps the text as the accessible name and shows only the icon. That's the simplest icon-only button with a name.

UIKit:

filterButton.accessibilityLabel = "Filter results"
shareButton.accessibilityLabel = "Share receipt"
closeButton.accessibilityLabel = "Close"

A repeated icon names its object. For a favorite button the action is on/off, so it's a toggle with a stable name:

Toggle(isOn: $tea.isFavorite) {
    Label("Favorite \(tea.name)", systemImage: tea.isFavorite ? "heart.fill" : "heart")
}
.toggleStyle(.button)
.labelStyle(.iconOnly)

When the visible text and the label differ, the visible text stays a valid Voice Control command:

addToCartButton.accessibilityLabel = "Add jasmine tea to cart"
addToCartButton.accessibilityUserInputLabels = ["Add to cart", "Add jasmine tea"]

Check

Profile:   VoiceOver
Task:      swipe through the toolbar and one list
Expected:  every icon button has a task name
           no asset or symbol names
           repeated icons name their object
Profile:   Voice Control
Task:      activate each icon button by name
Expected:  each command works
           repeated controls can be told apart
Profile:   another language (for example German)
Task:      the same screen
Expected:  labels are translated, no English or identifiers leak through

Pitfalls

  1. Not by shape: "slider icon".
  2. Not by implementation: filterButton.
  3. No role in the label: "Filter button".
  4. No identical labels on 10 favorite buttons.
  5. No accessibilityIdentifier as a label.
  6. No label that contradicts the visible text.

WCAG mapping

  1. 4.1.2 Name, Role, Value: the button has a name and a role.
  2. 1.1.1 Non-text Content: the icon has a text alternative.
  3. 2.5.3 Label in Name: the accessible name contains the visible text.
  4. 2.4.6 Headings and Labels: the label describes the purpose.
  1. Mystery Icon
  2. Duplicate Voice Command
  3. Label Soup
  1. Chapter 3
  2. Chapter 8
  3. Chapter 10
  4. Chapter 11

Sources

  1. Apple Developer: accessibilityLabel
  2. Apple Developer: accessibilityInputLabels
  3. Apple Human Interface Guidelines: Icons