Skip to content

Paywall close button has no accessibility label or identifier #7348

Description

@vanajmoorthy

Describe the bug

The close (X) button on the RevenueCatUI paywall doesn't have an accessibility label or an accessibility identifier.

It's rendered in PaywallView.swift (makeToolbar) as just an SF Symbol:

Button {
    onRequestedDismissal()
} label: {
    Image(systemName: "xmark")
}

Since the label is only the xmark image, VoiceOver reads it as an unlabelled button, so a screen reader user has no way to tell what it does. There's no accessibility identifier either, so it can't be targeted in UI tests.

Your Customer Center already handles this properly (its close button sets both accessibilityIdentifier("circled_close_button") and an accessibilityLabel), so it looks like the paywall templates just got missed.

Would be great to add an accessibility label to the paywall close button, and ideally an identifier too.

Platform

iOS

SDK version

RevenueCatUI 5.67.1 (via react-native-purchases 9.15.2)

SDK integration method

CocoaPods

StoreKit version

StoreKit 2 (default on versions >=5.0.0)

OS version

iOS 17+ (version-independent)

Xcode version

26.2

Device and/or simulator

Device

Environment

Sandbox

How widespread is the issue

100%, it's on every paywall that shows a close button.

Debug logs

Nothing to attach here, it's not a runtime error, just a missing accessibility label in the UI. I found it by looking at the paywall's accessibility tree and the RevenueCatUI source.

Steps to reproduce

  1. Show a RevenueCatUI paywall with a close button (displayCloseButton: true).
  2. Turn on VoiceOver and focus the X in the top right, or open it in Accessibility Inspector.

Expected: it reads out something meaningful like "Dismiss" (the way the Customer Center close button does), and has an accessibility identifier for testing.
Actual: no label (VoiceOver just says it's a button/image) and no identifier.

Other information

We're still on 5.67.1, but I checked the latest release (5.83.0) and it's the same code, makeToolbar still renders the close as Image(systemName: "xmark") with nothing attached, so it isn't fixed yet.

There's already a pattern to copy for the fix: in CustomerCenter/ButtonStyles.swift the close button sets .accessibilityLabel(Text(localization[.dismiss])) and .accessibilityIdentifier("circled_close_button"). Doing the same on the paywall toolbar button should cover it.

Additional context

This also affects the hybrid SDKs (react-native-purchases-ui etc.) since they render the same native paywall. The main thing for us is the VoiceOver label; the identifier would be a nice bonus so we can dismiss the paywall in UI tests without relying on blind coordinate taps.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions