VoiceOver reads out all visible content on the screen, which is essential for visually challenged users. However, this raises a privacy concern—what if a user accidentally focuses on sensitive information, like a bank account password, and it gets read aloud?
How can developers prevent VoiceOver from exposing confidential data while still maintaining accessibility? Are there best practices or recommended approaches to handle such scenarios effectively?
General
RSS for tagExplore best practices for creating inclusive apps that cater to users with diverse abilities
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
I have implemented a SwiftUI view containing a grid of TextField elements, where focus moves automatically to the next field upon input. This behavior works well on iOS 16 and 17, maintaining proper focus highlighting when keyboard full access is enabled.
However, in iOS 18 and above, the keyboard full access focus behaves differently. It always stays behind the actual focus state, causing a mismatch between the visually highlighted field and the active text input. This leads to usability issues, especially for users navigating with an external keyboard.
Below is the SwiftUI code for reference:
struct AutoFocusGridTextFieldsView: View {
private let fieldCount: Int
private let columns: Int
@State private var textFields: [String]
@FocusState private var focusedField: Int?
init(fieldCount: Int = 17, columns: Int = 5) {
self.fieldCount = fieldCount
self.columns = columns
_textFields = State(initialValue: Array(repeating: "", count: fieldCount))
}
var body: some View {
let rows = (fieldCount / columns) + (fieldCount % columns == 0 ? 0 : 1)
VStack(spacing: 10) {
ForEach(0..<rows, id: \.self) { row in
HStack(spacing: 10) {
ForEach(0..<columns, id: \.self) { col in
let index = row * columns + col
if index < fieldCount {
TextField("", text: $textFields[index])
.frame(width: 40, height: 40)
.multilineTextAlignment(.center)
.textFieldStyle(RoundedBorderTextFieldStyle())
.focused($focusedField, equals: index)
.onChange(of: textFields[index]) { newValue in
if newValue.count > 1 {
textFields[index] = String(newValue.prefix(1))
}
if !textFields[index].isEmpty {
moveToNextField(from: index)
}
}
}
}
}
}
}
.padding()
.onAppear {
focusedField = 0
}
}
private func moveToNextField(from index: Int) {
if index + 1 < fieldCount {
focusedField = index + 1
}
}
}
struct AutoFocusGridTextFieldsView_Previews: PreviewProvider {
static var previews: some View {
AutoFocusGridTextFieldsView(fieldCount: 10, columns: 5)
}
}
Has anyone else encountered this issue with FocusState in iOS 18?
I really do believe that this is a bug strictly connected to keyboard navigation since I experienced similar problem also on UIKit equivalent of the view.
Any insights or suggestions would be greatly appreciated!
I am trying to implement voice over to my game, and have encountered an issue where a static text will take focus of all other interactions. I have a tutorial scene where I have one short "static text" accessibility node, but rest of gameplay is without such. This static text field occupies small part of screen and works fine, but I am not able to click on anything else, including any of my gameplay elements, wherever on the screen I click, it just re-highlights that static text.
It there a requirement for all elements to use Accessibility Nodes and can't have mixed setup with some not having them ?
How can I get around it?
Question number 2: What decides which Accessibility node gets selected when entering a new UI screen, I have multiple buttons and am observing rather random behaviour, every time different button is highlighted first.
Question number 3: The plugin documentation mentiones runtime support in play mode, are there any specific steps for this to work as I can't seem to be able to. I have VoiceOver enabled on macOS unity is on macOS (also tried iOS) platform but it doesn't seem to do anything. Note my buttons and label accessibility nodes work correctly on iOS build.
Thanks in advance for any help
I can’t screenshot using assistive touch after i install ios 26 beta 2
Hello,
When I listen to title in my app with VoiceOver, it makes a strange sound.
This characters make with Korean+number+Alphabet.
Is this combination makes some strange sound with voice over?
I would like to ask if Apple can fix this issue.
Thank you.
Topic:
Accessibility & Inclusion
SubTopic:
General
Hi everyone,
I completed my Apple Developer registration on November 8, 2025, and paid the fee. Afterwards, I was charged another €99, so I basically paid twice. But nothing has changed on my account so far — it doesn’t even show as “pending” or “waiting” anymore. I also can’t reach Apple Support, since I’m unable to get a call or send an email.
Has anyone else experienced something like this or knows what I can do?
Topic:
Accessibility & Inclusion
SubTopic:
General
Your app's binary includes references to HealthKit components, but the app still does not appear to include any primary features that require health or fitness data.
Next Steps
To resolve this issue, please remove any HealthKit functionality from the app, as well as any references to this app’s interactivity with HealthKit from the app or its metadata. This includes removing any HealthKit-related keys in the app's Info.plist or InfoPlist.strings files, as well as removing any calls to HealthKit APIs, including those from third-party platforms, from the app.
Topic:
Accessibility & Inclusion
SubTopic:
General
I’m trying to add the .header accessibility trait to a UISegmentedControl so that VoiceOver recognizes it accordingly. However, setting the trait using the following code doesn’t seem to have any effect:
segmentControl.accessibilityTraits = segmentControl.accessibilityTraits.union(.header)
Even after applying this, VoiceOver doesn’t announce it as a header. Is there any workaround or recommended approach to achieve this?
After IOS 26 beta 2 installation in my iphone 13, I can't do a screenshot using assistivetouch nor touch on back.
Currently i am using an iphone 15 pro which is just 7 months old but it was good till this month it was at 97% even after using more than 6 months, but in recent fews days it is regularly dropping by 1% every day and now it is at 89% only with 10 to 12 days it dropped by 8% . Is my battery defective or something is wrong with my phone .
bcoz of this i am very upset because of this bad decrease of battery health . i have heard it is normal to degrade by 1% monthly but mine is dropping daily its soo frustrating.
and if my battery reaches under 80% within the warrenty period?
will get a free battery replacement from apple or not ? I don’t have apple care+ .
But its under 1 year standard warrenty .
please reply apple as its soo frustrating
When iOS screen reader reads the month "July" in its shorter version "Jul" its not reading it correctly as month, where as all other months name it reading it correctly in shorter version, so as a result all dates comes under that month when we display in front end and use a screen reader to read it then it will read out as number not date.
I have tried the longer version with the screen reader and then its reads correctly July as well.
Topic:
Accessibility & Inclusion
SubTopic:
General
In SwiftUI, the date picker component is breaking in colour contrast accessibility. Below code has been use to create date picker:
struct ContentView: View {
@State private var date = Date()
@State private var selectedDate: Date = .init()
var body: some View {
let min = Calendar.current.date(byAdding: .day, value: 14, to: Date()) ?? Date()
let max = Calendar.current.date(byAdding: .year, value: 4, to: Date()) ?? Date()
DatePicker(
"Start Date",
selection: $date,
in: min ... max,
displayedComponents: [.date]
)
.datePickerStyle(.graphical)
.frame(alignment: .topLeading)
.onAppear {
selectedDate = Calendar.current.date(byAdding: .day, value: 14, to: Date()) ?? Date()
}
}
}
#Preview {
ContentView()
}
attaching the screenshot of failure accessibility.
Should I allow the CIJSULAgent to find devices on local network?
Hi! I have noticed a few glitches as well as some overall unfortunate cons with the assistive access mode.
Alarms, timers, stopwatch, etc. do not sound or alert. However, I have an infant monitor app and I do get that sound alert so I know it is possible.. do I need to download a separate alarm app for it to work?
Cannot make FaceTime calls with favorite contacts.
Find My iPhone cannot jump to the maps app.
Camera cannot zoom in or out.
Photos cannot be deleted, edited, or shared in a shared album in the photos app.
Photos/videos cannot be sent in messages.
Spotify cannot be accessed from the lock screen.
Apps do not stay open if you lock the phone screen or leave it on too long without touching the screen (auto locks).
There is no flashlight option. I downloaded an app to have this feature but without being touched the screen will lock which shuts off the flashlight feature in the app until I unlock the phone again.
The only way I found to make the accessibility focus work correctly in the detent in a fullscreen cover is to apply the focus manually. The issue is in the ContentView the grabber works while in the fullscreen it does not. Is there something I am missing or is this a bug. I also don't understand why I need to apply focus in the fullscreen cover while in the ContentView I do not.
struct ContentView: View {
@State private var buttonClicked = false
@State private var bottomSheetShowing = false
var body: some View {
NavigationView {
VStack {
Button(action: {
buttonClicked = true
}, label: {
Text("First Page Button")
.padding()
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(8)
})
.accessibilityLabel("First Page Button")
FullscreenView2()
}
.navigationTitle("Welcome")
.fullScreenCover(isPresented: $buttonClicked) {
FullscreenView(buttonClicked: $buttonClicked, bottomSheetShowing: $bottomSheetShowing)
}
}
}
}
struct FullscreenView: View {
@Binding var buttonClicked: Bool
@Binding var bottomSheetShowing: Bool
var body: some View {
NavigationView {
VStack {
Button(action: {
bottomSheetShowing = true
}, label: {
Text("Show Bottom Sheet")
.padding()
.background(Color.green)
.foregroundColor(.white)
.cornerRadius(8)
})
}
.accessibilityHidden(bottomSheetShowing)
.navigationTitle("Fullscreen View")
.toolbar {
ToolbarItem(placement: .navigationBarLeading) {
Button(action: {
buttonClicked = false
}, label: {
Text("Close")
})
.accessibilityLabel("Close Fullscreen View Button")
}
}
.accessibilityHidden(bottomSheetShowing)
.onChange(of: bottomSheetShowing, perform: { _ in })
.sheet(isPresented: $bottomSheetShowing) {
if #available(iOS 16.0, *) {
BottomSheetView(bottomSheetShowing: $bottomSheetShowing)
.presentationDetents([.medium, .large])
} else {
BottomSheetView(bottomSheetShowing: $bottomSheetShowing)
}
}
}
}
}
struct FullscreenView2: View {
@State var bottomSheetShowing = false
var body: some View {
VStack {
Button(action: {
bottomSheetShowing = true
}, label: {
Text("Show Bottom Sheet")
.padding()
.background(Color.green)
.foregroundColor(.white)
.cornerRadius(8)
})
}
.accessibilityHidden(bottomSheetShowing)
.navigationTitle("Fullscreen View")
//.accessibilityHidden(bottomSheetShowing)
.onChange(of: bottomSheetShowing, perform: { _ in })
.sheet(isPresented: $bottomSheetShowing) {
if #available(iOS 16.0, *) {
BottomSheetView(bottomSheetShowing: $bottomSheetShowing)
.presentationDetents([.medium, .large])
} else {
BottomSheetView(bottomSheetShowing: $bottomSheetShowing)
}
}
}
}
struct BottomSheetView: View {
@Binding var bottomSheetShowing: Bool
// @AccessibilityFocusState var isFocused: Bool
var body: some View {
VStack(spacing: 20) {
Text("Bottom Sheet")
.font(.headline)
.accessibilityAddTraits(.isHeader)
Button(action: {
bottomSheetShowing = false
}, label: {
Text("Dismiss")
.padding()
.background(Color.red)
.foregroundColor(.white)
.cornerRadius(8)
})
.accessibilityLabel("Dismiss Bottom Sheet Button")
}
.padding()
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(
Color(UIColor.systemBackground)
.edgesIgnoringSafeArea(.all)
)
.accessibilityAddTraits(.isModal) // Indicates that this view is a modal
// .onAppear {
// // Set initial accessibility focus when the sheet appears
// DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
// isFocused = true
// }
// }
// .accessibilityFocused($isFocused)
}
}
Topic:
Accessibility & Inclusion
SubTopic:
General
Hi,
I am setting an accessibilityLabel and accessibilityHint property of a UIAlertAction. However, VoiceOver is only reading the label out. Usually, the label is read out, followed by a short pause and then the hint. Is this a known issue, where hints do not work for this element? I can append the hint to the label, but interested to know if there's something I'm doing wrong.
Regards.
Hey everyone
I'm working on a health app that's heavily focused on HRV tracking and analysis, and I'm trying to figure out what's actually possible with AirPods Pro 3 from a developer standpoint. The hardware clearly has a much better heart rate sensor than the previous generation, but I'm hitting some walls when it comes to actually accessing the data I need.
So here's the situation I'm dealing with: When I query HealthKit for HRV samples, I'm not seeing anything coming from AirPods Pro 3. The device is obviously capable of tracking heart rate continuously during workouts and listening sessions, and from what I've read about the hardware, it should theoretically be able to capture the inter-beat intervals needed for HRV calculation. But either that data isn't being processed on-device, or it's just not being made available through the standard HealthKit data types that third-party apps can access.
What I'm really after is either direct HRV metrics (like SDNN, which Apple Watch already provides through HKQuantityTypeIdentifierHeartRateVariabilitySDNN) or even better, access to the raw R-R interval data. With R-R intervals, I could calculate RMSSD, pNN50, and other time-domain and frequency-domain HRV metrics that are super valuable for tracking recovery, autonomic nervous system balance, and stress levels. This would be especially useful since a lot of users wear AirPods during activities when they're not wearing their Apple Watch.
Has anyone managed to find a way to pull this data from AirPods Pro 3? Are there any private frameworks or entitlements I should be looking into? Or is this just fundamentally not exposed to developers at the OS level right now?
I've gone through the HealthKit documentation pretty thoroughly and haven't found anything that specifically addresses this, but I'm wondering if I'm missing something or if there are any known workarounds.
I'm also curious if anyone has heard anything from Apple about future plans to expose this data. It seems like a missed opportunity given how capable the hardware is and how much value developers could provide with access to this physiological data. Would love to hear if anyone else is working on similar features or has insights into the technical limitations here.
In iOS18, when a button using @FocusSate is inside a ScrollView and if this view is getting opened via NavigationLink,
The button is not accessible via Bluetooth (external) keyboard)
Is this a known isssue in iOS18
Topic:
Accessibility & Inclusion
SubTopic:
General
I’m trying to customize the keyboard focus appearance in SwiftUI.
In UIKit (see WWDC 2021 session Focus on iPad keyboard navigation), it’s possible to remove the default UIFocusHaloEffect and change a view’s appearance depending on whether it has focus or not.
In SwiftUI I’ve tried the following:
.focusable() // .focusable(true, interactions: .activate)
.focusEffectDisabled()
.focused($isFocused)
However, I’m running into several issues:
.focusable(true, interactions: .activate) causes an infinite loop, so keyboard navigation stops responding
.focusEffectDisabled() doesn’t seem to remove the default focus effect on iOS
Using @FocusState prevents Space from triggering the action when the view has keyboard focus
My main questions:
How can I reliably detect whether a SwiftUI view has keyboard focus? (Is there an alternative to FocusState that integrates better with keyboard navigation on iOS?)
What’s the recommended way in SwiftUI to disable the default focus effect (the blue overlay) and replace it with a custom border?
Any guidance or best practices would be greatly appreciated!
Here's my sample code:
import SwiftUI
struct KeyboardFocusExample: View {
var body: some View {
// The ScrollView is required, otherwise the custom focus value resets to false after a few seconds. I also need it for my actual use case
ScrollView {
VStack {
Text("First button")
.keyboardFocus()
.button {
print("First button tapped")
}
Text("Second button")
.keyboardFocus()
.button {
print("Second button tapped")
}
}
}
}
}
// MARK: - Focus Modifier
struct KeyboardFocusModifier: ViewModifier {
@FocusState private var isFocused: Bool
func body(content: Content) -> some View {
content
.focusable() // ⚠️ Must come before .focused(), otherwise the FocusState won’t be recognized
// .focusable(true, interactions: .activate) // ⚠️ This causes an infinite loop, so keyboard navigation no longer responds
.focusEffectDisabled() // ⚠️ Has no effect on iOS
.focused($isFocused)
// Custom Halo effect
.padding(4)
.overlay(
RoundedRectangle(cornerRadius: 18)
.strokeBorder(
isFocused ? .red : .clear,
lineWidth: 2
)
)
.padding(-4)
}
}
extension View {
public func keyboardFocus() -> some View {
modifier(KeyboardFocusModifier())
}
}
// MARK: - Button Modifier
/// ⚠️ Using a Button view makes no difference
struct ButtonModifier: ViewModifier {
let action: () -> Void
func body(content: Content) -> some View {
content
.contentShape(Rectangle())
.onTapGesture {
action()
}
.accessibilityAction {
action()
}
.accessibilityAddTraits(.isButton)
.accessibilityElement(children: .combine)
.accessibilityRespondsToUserInteraction()
}
}
extension View {
public func button(action: @escaping () -> Void) -> some View {
modifier(ButtonModifier(action: action))
}
}
SwiftUI provides the accessibilityCustomContent(_:_:) modifier to add additional accessibility information for an element. However, I couldn’t find a similar approach in UIKit.
Is there a way to achieve this in UIKit?