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
- Show a RevenueCatUI paywall with a close button (displayCloseButton: true).
- 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.
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:
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
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
Additional context