Skip to content

Add accessibilityLabel override to AttributedLabel#625

Merged
RoyalPineapple merged 4 commits into
mainfrom
RoyalPineapple/create-pr
Jul 9, 2026
Merged

Add accessibilityLabel override to AttributedLabel#625
RoyalPineapple merged 4 commits into
mainfrom
RoyalPineapple/create-pr

Conversation

@RoyalPineapple

Copy link
Copy Markdown
Collaborator

Adds an optional accessibilityLabel: String? to the AttributedLabel model so consumers can override or suppress the label that is otherwise derived automatically from the displayed text. nil (the default) preserves today's text-derived behavior, a non-nil value overrides it, and "" suppresses the spoken label entirely — useful when the text is surfaced through accessibilityValue/accessibilityHint and the label is merged into a combined accessibility element, so the content isn't announced twice. The change is purely additive: no existing call sites change. Internally, the expensive text-derived label is cached behind the existing text-change guard in LabelView while the override is applied on every update, so an override change takes effect even when the text is unchanged, with no perf regression. Adds tests covering the default/override/suppression cases, application without a text change, and suppression flowing through AccessibilityComposition.

@RoyalPineapple RoyalPineapple marked this pull request as ready for review July 7, 2026 14:34
@RoyalPineapple RoyalPineapple requested a review from a team as a code owner July 7, 2026 14:34

@robmaceachern robmaceachern left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

/// is useful when the text is surfaced through `accessibilityValue` / `accessibilityHint`
/// instead, so the content is not announced twice (e.g. when this label is merged into a
/// combined accessibility element).
public var accessibilityLabel: String?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 (on Rob's behalf) The String? shape is the right call here — it's consistent with the sibling accessibilityValue/accessibilityHint on this model, with AccessibilityElement.label, and with UIKit's own accessibilityLabel (nil = derive). And empty-string-means-absent is already the house convention: AccessibilityCombine documents that an element isn't accessible "unless it has a non-nil and non-empty label/value/hint," which is exactly why the composition test works. So the ""-suppresses behavior isn't a novel magic value — it fits existing precedent. I'd keep it over an enum, which would make this the only accessibility prop that isn't a plain optional string and would lose the x.accessibilityLabel = someOptionalString drop-in ergonomics.

One small discoverability nit: ""-as-suppression isn't legible at the call site, and a future reader could "fix" a bare "" thinking it's a mistake. Consider a named constant so intent is greppable:

extension AttributedLabel {
    /// Assign to `accessibilityLabel` to suppress the spoken label entirely.
    public static let suppressedAccessibilityLabel = ""
}

Non-blocking — the doc comment already covers it well.


func test_accessibilityLabel_suppressed() {
// An empty string suppresses the spoken label entirely: the backing view reports "",
// *not* the displayed text. (UILabel returns an explicitly-set empty string verbatim,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 (on Rob's behalf) Good that this is called out inline — the whole suppression story rests on this undocumented UIKit behavior (an explicitly-set "" is returned verbatim rather than falling back to .text). That makes this test load-bearing rather than incidental: if a future OS changed the fallback, ""-suppression would silently break. Worth keeping and maybe a one-liner in the test name/doc flagging it as guarding a UIKit assumption.

@RoyalPineapple RoyalPineapple force-pushed the RoyalPineapple/create-pr branch from 861794d to 2020962 Compare July 9, 2026 11:00
@RoyalPineapple RoyalPineapple enabled auto-merge July 9, 2026 12:57
RoyalPineapple and others added 4 commits July 9, 2026 15:32
Adds an optional `accessibilityLabel: String?` to the AttributedLabel
model: `nil` (default) derives the label from the displayed text as
before, a non-nil value overrides it, and `""` suppresses the spoken
label entirely (useful when content is surfaced via accessibilityValue
and the label is merged into a combined accessibility element).

The expensive text-derived label is now cached behind the existing
text-change guard in LabelView, while the override is applied on every
update so a change takes effect even when the text is unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add AttributedLabel/Label.suppressedAccessibilityLabel so the "" suppression
value is greppable and legible at the call site (per Rob's review), and rename
the suppression test to flag that it guards an undocumented UIKit behavior.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@RoyalPineapple RoyalPineapple force-pushed the RoyalPineapple/create-pr branch from 2020962 to d0a313d Compare July 9, 2026 13:32
@RoyalPineapple RoyalPineapple merged commit bbd0158 into main Jul 9, 2026
10 checks passed
@RoyalPineapple RoyalPineapple deleted the RoyalPineapple/create-pr branch July 9, 2026 13:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants