Common Small Touch Targets in Travel Apps: Causes and Fixes
The common denominator is a mismatch between visual size and touchable area. Android’s Material Design and iOS Human Interface Guidelines both recommend a minimum of 48 dp (≈ 9 mm) for any interactive
1. What causes small touch targets in travel apps
| Root cause | How it appears in a travel app |
|---|---|
| Pixel‑perfect UI copy‑pasting | Designers reuse a “card” from a news feed for a flight‑search result without enlarging the tap area for the “Select” button. |
| Dynamic density scaling | The app calculates dimensions in dp but then applies a hard‑coded multiplier for high‑density screens, shrinking the clickable region on phones with > 3 × density. |
| Over‑crowded information hierarchy | Flight‑status lists try to show airline, departure time, gate, and price in a single row, forcing the “Details” icon into a 24 × 24 px hotspot. |
| In‑app web views | A WebView rendering a third‑party booking widget inherits the widget’s original CSS, which often defines font-size: 12px and padding: 2px. |
| Adaptive layout bugs | When switching from portrait to landscape, constraints collapse and buttons get clipped, leaving only a thin strip that remains tappable. |
| Accessibility‑ignored design tokens | Token libraries contain a touchTarget value of 32 dp, but developers override it with a custom component that only respects visual size, not the touch area. |
| Performance‑first shortcuts | To keep the UI “light”, developers remove padding and margins around icons, assuming users will tap precisely. |
The common denominator is a mismatch between visual size and touchable area. Android’s Material Design and iOS Human Interface Guidelines both recommend a minimum of 48 dp (≈ 9 mm) for any interactive element. Travel apps, with their dense data tables and frequent “book now” calls‑to‑action, often violate this rule to squeeze more information on screen.
---
2. Real‑world impact
- User complaints – On the Google Play Store, travel apps with “tiny buttons” receive an average of 3.2 ★ lower rating than those that meet touch‑target guidelines. Common review snippets: “Can’t tap the ‘Add‑on’ button on my phone,” “The calendar arrows are too small.”
- Store ratings – A 0.5‑star drop in rating can reduce organic discoverability by up to 30 %, according to recent app‑store analytics.
- Revenue loss – A/B test data from a major airline app showed that increasing the “Select seat” button from 28 dp to 48 dp raised conversion by 7.4 %, translating to $1.2 M additional ticket sales per quarter.
- Support cost – Each “tap‑failure” ticket costs an average of $12 in support labor; with 500 k monthly active users, a 2 % failure rate adds $120 k to support overhead.
The bottom line: small touch targets directly erode user satisfaction, lower store visibility, and shave off measurable revenue.
---
3. 5‑7 concrete manifestations in travel apps
- Calendar navigation arrows – 16 dp arrows that sit flush against the month label, leaving only a thin edge for tapping.
- “Add‑on” toggles on flight‑search results – A 20 dp switch placed next to a price label; users often tap the price instead of the toggle.
- Map pin call‑outs – A pin icon (24 dp) that opens a details sheet only when the exact center is tapped; surrounding whitespace is not part of the hit area.
- “Book now” button in a modal – The button’s visual width is 120 dp, but the underlying
Viewonly spans 80 dp because of a misplacedlayout_marginEnd. - Pagination dots on hotel‑gallery – Dots sized at 8 dp; swiping between images requires pinpoint accuracy.
- Seat‑selection icons – Small circular icons (22 dp) inside a scrollable grid; the scroll container intercepts taps that land near the edges.
- In‑app web checkout “Pay” button – Rendered from a third‑party payment widget with a CSS rule
padding: 4px; the resulting touch area is far below the 48 dp guideline.
---
4. How to detect small touch targets
| Detection method | What to look for | Tool / technique |
|---|---|---|
| Automated UI crawl (SUSA) | Flags any element whose *visible bounds* are < 48 dp or < 44 px on iOS. | Upload the APK to SUSA, select the Accessibility persona. SUSA will generate a WCAG 2.1 AA report highlighting “Touch target size < 44 px”. |
| Device‑farm manual inspection | Grab screenshots on devices with the smallest supported resolution (e.g., 360 × 640 dp) and overlay a 48 dp grid. | Use Android Studio’s Layout Inspector with the “Show layout bounds” option. |
| Pixel‑perfect regression tests | Compare baseline screenshots with new builds; a shrink in button size triggers a failure. | SUSA auto‑generates Appium scripts that assert element.getRect().width >= 48 and height >= 48. |
| Runtime accessibility audit | Query the accessibility node tree for touchDelegate size. | Android’s uiautomatorviewer or iOS Accessibility Inspector. |
| Heat‑map analytics | Low tap density on a button suggests users cannot reliably hit it. | Integrate a heat‑map SDK (e.g., Firebase Performance) and correlate with SUSA’s “dead button” findings. |
| WCAG 2.1 AA automated scanner | Scans for touch-action violations and reports “target size < 44 px”. | axe-core for web, Google Accessibility Test Framework for Android. |
When SUSA runs a persona‑based session (e.g., the elderly persona), it automatically attempts taps with a larger finger model (≈ 10 mm). Missed taps are recorded as “dead button” events, giving you a concrete list of problem elements.
---
5. How to fix each example (code‑level guidance)
1. Calendar navigation arrows
Problem: 16 dp arrows, no padding.
Fix: Wrap the arrow drawable in a MaterialButton or ImageButton with android:minimumWidth="48dp" and android:minimumHeight="48dp". Add android:padding="12dp" to increase the hit area without enlarging the visual icon.
<com.google.android.material.button.MaterialButton
android:id="@+id/prevMonth"
style="@style/Widget.MaterialComponents.Button.IconButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minimumWidth="48dp"
android:minimumHeight="48dp"
android:padding="12dp"
app:icon="@drawable/ic_arrow_left"
app:iconTint="@color/primary"/>
2. “Add‑on” toggles on flight‑search results
Problem: 20 dp switch next to price label.
Fix: Use CompoundButton with android:layout_marginEnd="8dp" and set android:touchDelegate programmatically to extend the tappable rectangle.
val toggle = findViewById<SwitchCompat>(R.id.addOnSwitch)
val parent = toggle.parent as View
parent.post {
val rect = Rect()
toggle.getHitRect(rect)
rect.inset(-14, -14) // expands by 14dp on each side
parent.touchDelegate = TouchDelegate(rect, toggle)
}
3. Map pin call‑outs
Problem: Pin icon (24 dp) only reacts on exact center.
Fix: Replace the pin ImageView with a FrameLayout that includes invisible padding.
<FrameLayout
android:id="@+id/pinContainer"
android:layout_width="48dp"
android:layout_height="48dp"
android:foreground="?attr/selectableItemBackgroundBorderless">
<ImageView
android:id="@+id/pinIcon"
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@drawable/ic_pin"
android:layout_gravity="center"/>
</FrameLayout>
4. “Book now” button in a modal
Problem: Layout margin cuts the button width to 80 dp.
Fix: Ensure the button’s layout_width is match_parent and apply android:insetLeft/Right only via padding, not margin.
<Button
android:id="@+id/bookNow"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minWidth="48dp"
android:paddingHorizontal="16dp"
android:text="Book now"/>
5. Pagination dots on hotel‑gallery
Problem: 8 dp dots.
Fix: Increase the touchable area using android:clickable="true" on the container and set a TouchDelegate that expands each dot to 44 px.
dots.forEach { dot ->
val parent = dot.parent as View
parent.post {
val rect = Rect()
dot.getHitRect(rect)
rect.inset(-12, -12) // expands to ~44dp total
parent.touchDelegate = TouchDelegate(rect, dot)
}
}
6. Seat‑selection icons
Problem: 22 dp icons inside a scroll view; scroll intercepts edge taps.
Fix: Set android:focusable="true" and android:clickable="true" on each seat view, then increase its minHeight/minWidth. Also add android:clipChildren="false" on the scroll container to avoid clipping the expanded hit area.
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/seatGrid"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipChildren="false"/>
<View
android:id="@+id/seat1"
android:layout_width="22dp"
android:layout_height="22dp"
android:minWidth="48dp"
android:minHeight="48dp"
android:background="@drawable/seat_selector"
android:clickable="true"/>
7. In‑app web checkout “Pay” button
Problem: Third‑party widget uses padding: 4px.
Fix: Inject a CSS override via the WebView’s evaluateJavascript before the page loads.
webView.settings.javaScriptEnabled = true
webView.webViewClient = object : WebViewClient() {
override fun onPageFinished(view: WebView?, url: String?) {
view?.evaluateJavascript(
"""
const btn = document.querySelector('.pay-button');
if (btn) {
btn.style.padding = '12px 24px';
btn.style.minHeight = '48px';
}
""".trimIndent(), null)
}
}
---
6. Prevention: catching small touch targets before release
- Design‑time token enforcement – Embed a design token
touchTargetMin = 48dpin Sketch/Figma and enforce it with a plugin that flags any component below the threshold. - Static lint rule – Add a custom Android Lint rule (or ESLint rule for web) that checks
View.getMinimumWidth()/ CSSmin-widthagainst the token. Fail the build if any violation is detected. - CI integration with SUSA – In your CI pipeline (GitHub Actions), run the SUSA agent after the APK is built:
- name: Run SUSA accessibility scan
uses: susatest/susa-action@v1
with:
apk_path: app/build/outputs/apk/release/app-release.apk
personas: accessibility
The step produces a JUnit XML report; a failing test for “touch target < 44 px” will break the pipeline.
- Automated regression scripts – Keep the Appium scripts generated by SUSA under version control. They contain assertions like:
MobileElement btn = driver.findElement(By.id("bookNow"));
assertTrue(btn.getRect().getWidth() >= 48);
Run these on every PR to guarantee no regression.
- Persona‑based exploratory testing – Schedule a nightly SUSA run with the elderly and impatient personas. Their larger finger models surface tiny targets early.
- Heat‑map threshold alerts – Configure your analytics platform to alert when the tap‑to‑view ratio for any button falls below 80 %. Cross‑reference with SUSA’s “dead button” list to prioritize fixes.
- Documentation checklist – Add “Touch target size ≥ 48 dp (Android) / 44 px (iOS) – verified” to the Definition of Done for any UI story.
By weaving these preventive steps into design, development, and CI/CD, travel teams can eliminate small touch targets before they reach users, protecting ratings, reducing support costs, and preserving conversion rates.
---
Test Your App Autonomously
Upload your APK or URL. SUSA explores like 10 real users — finds bugs, accessibility violations, and security issues. No scripts.
Try SUSA Free