
How to build a successful iOS app using overlooked features

14. Mar 2025
iOSNowadays, mobile apps are our digital extended arm - we use them to get work done, communicate, shop, and entertain ourselves. But what if some users can't access these capabilities simply because the app design doesn't account for their needs?
Accessibility isn't just a formal requirement - it's a mindset that ensures applications are usable by all, regardless of visual 👁️, motor 👏🏽, auditory 👂🏽 or cognitive 🧠 disabilities. ✨ In this article, we will show a concrete example where we compare an inaccessible and an accessible screen of a mobile app.
🔍 You will learn:
✔️ What makes an app inaccessible and what obstacles it creates 🚧
✔️ What a tweaked, accessible version might look like 💡
✔️ Practical tips you can apply in your projects 🛠️
Whether you're a designer, developer or product manager, understanding these principles will help you create apps that don't segregate, but connect. Let's do it! 🚀
Let's look at the numbers:
First of all, let's see what it looks like when you first enter.
In the image on the left, the first problem can be seen right at the start. The inaccessible screen jumps first when you enter to photo and reads the accessible title, which in this case is omitted, so the Screen Reader only reads "Photo, Space". Since this is a photo from a URL, there is no way to go into assets and name the photo directly there. (If the photo were named apple.jpg, the file name would be used for the unspecified accessible name.) Then, after reading, it jumps right to the heart button under the apple image and reads "Like, Button".
This approach has several shortcomings:
On the right, you'll notice that once I've accessed the "apple" item, I'm moving on to the item's primary action, and that's adding it to the cart. The Screen Reader reads, "Add to Cart product Apple". This button gives the user full context and knows exactly what to expect when the button is pressed. We achieved this by ignoring the image in the content and adding descriptions of each component dynamically according to the content.
// Modifier applied to the image component.
.accessibilityHidden(true)
// Modifier used on the add to cart button component.
.accessibilityLabel("Pridať do košíka produkt \(productName)")
Let's see what it looks like with the information that is written in the table.
As soon as I want to read the contents of the table, I very quickly find that even though visually the table works, when I start cycling through the elements, it reads "Hmotnosť" first and then "Farba" right after that, before moving on to the next row where it reads "125g" and "Červená".
Grid {
GridRow {
VStack {
Text("Hmotnosť")
Text("125 g")
}
VStack {
Text("Farba")
Text("Červená")
}
}
GridRow {
VStack {
Text("Krajina pôvodu")
Text("Slovensko")
}
VStack {
Text("Nutričné hodnoty")
Text("52 kcal")
}
}
}
Again, the confusion of the user going through this screen must be immense.
On the right, we have made reading content accessible by combining the title and value in the table into a single accessibility group. This results in the Screen Reader automatically reading, "Hmotnosť: 125g".
Grid {
GridRow {
VStack {
Text("Hmotnosť")
Text("125 g")
}
.accessibilityElement(children: .combine)
VStack {
Text("Farba")
Text("Červená")
}
.accessibilityElement(children: .combine)
}
GridRow {
VStack {
Text("Krajina pôvodu")
Text("Slovensko")
}
.accessibilityElement(children: .combine)
VStack {
Text("Nutričné hodnoty")
Text("52 kcal")
}
.accessibilityElement(children: .combine)
}
}
The integrity of this information will make for a completely different app experience for the user.
Next, we look at a simple product evaluation component.
When I move in the inaccessible flow to the rating component, it automatically moves me to the first star as the first action button from the component and the reader will report: "Add to favorites, Button".
When I start scrolling from left to right, it reports the same thing on every star. It is very difficult to impossible for a blind person to figure out what is happening on the screen.
@State var rating: Int = 1
var body: some View {
HStack {
ForEach(1..<6) { index in
Button(action: { rating = index }) {
Image(systemName: index <= rating ? "star.fill" : "star")
}
}
}
}
Again, the user is confused because they don't know what the buttons do. In the worst case, he thinks they are doing what the reader said: adding to favourites, while he will think he is adding the product to favourites, but in reality he will be sending a rating that does not reflect his real opinion.
In the accessible flow, we've grouped the rating component and added the "adjustable" flag to it.
Once we move to the rating in the accessible flow, the reader will say: "Product rating apple 1 out of 5, adjustable". This indicates to the user that:
@State var rating: Int = 1
var body: some View {
HStack {
ForEach(1..<6) { index in
Button(action: { rating = index }) {
Image(systemName: index <= rating ? "star.fill" : "star")
}
}
}
.accessibilityElement()
.accessibilityLabel(Text("Hodnotenie"))
.accessibilityValue(Text(String(rating) + " z 5"))
.accessibilityAdjustableAction { direction in
switch direction {
case .increment:
guard rating < 5 else { break }
rating += 1
case .decrement:
guard rating > 1 else { break }
rating -= 1
@unknown default:
break
}
}
}
As developers, we have a huge influence on whether an app will be usable by everyone, or whether it will simply be inaccessible to some users. As we've seen in the examples, often all it takes is a few tweaks to the code - properly set attributes, thoughtful navigation, or appropriate element state management - and the application becomes much more understandable to those who rely on assistive technologies. 🛠️📱
When developing, it's important to think about:
✔️ Logical navigation - elements must be read in a meaningful order
✔️ Proper labeling of components - a Screen Reader needs clear descriptions
✔️ Interactive elements - buttons, tables and forms need to have clear functionality
✔️ Grouping of elements - relevant information should be linked to make sense without visual context
Accessibility is not just a 'nice-to-have' - in many cases it is a legislative requirement and not least good software engineering. Well-written code means better scalability, sustainability and better usability for all.
So the next time you implement new functionality, ask yourself:
➡️ "Will this work for someone who can't see the screen?"
➡️ "Can a user understand the functionality using only a Screen Reader?"
➡️ "Do the navigation and interactions make sense even without the visual layout?"
If not, maybe it's time to add a few accessibility fixes. Small changes in code often make a huge difference in user experience. 🔥
💡 Source code can be found on GitHub.