WCAG 3.2.3 Consistent Navigation — Testing Guide for Mobile & Web Apps
WCAG 3.2.3 Consistent Navigation (Level AA) requires that navigational mechanisms that are repeated on multiple pages within a set of web pages occur in the same relative order each time they are repe
Understanding WCAG 3.2.3 Consistent Navigation
WCAG 3.2.3 Consistent Navigation (Level AA) requires that navigational mechanisms that are repeated on multiple pages within a set of web pages occur in the same relative order each time they are repeated, unless a change is initiated by the user. The same principle applies to mobile apps: any UI component that serves as a navigation aid (menus, tabs, drawers, bottom bars, etc.) must appear in a predictable location and order across screens that belong to the same logical flow or screen set.
In plain language, if a user learns where to find the main menu on one screen, they should be able to find it in the same spot on every other screen that is part of the same app or site, unless they deliberately choose to hide or reorder it. This predictability reduces cognitive load, helps users with memory or attention impairments, and supports people who rely on screen readers or voice control to build a mental model of the interface.
Who benefits?
- Users with short‑term memory loss, traumatic brain injury, or cognitive disabilities who depend on consistent cues.
- People who navigate via keyboard, switch devices, or voice commands and need to know where the next focus will land.
- Screen‑reader users who rely on predictable heading and landmark order to jump between sections.
- Older adults whose working memory declines with age.
- Power users who develop muscle memory for frequent actions; inconsistency forces them to re‑learn each time.
Real‑world impact when the rule is broken: a user may miss a primary navigation item, become stuck in a dead‑end flow, or trigger an unintended action because a button they expected in the footer appears in the header on a particular screen. In e‑commerce, this can lead to abandoned carts; in banking apps, it can cause failed transactions; in healthcare portals, it may prevent timely access to critical information.
Legal relevance: WCAG 3.2.3 is referenced by the EU European Accessibility Act (EAA) and its harmonized standard EN 301 549, as well as by the Americans with Disabilities Act (ADA) Title III interpretations that treat WCAG conformance as evidence of reasonable accommodation. Non‑conformance can expose organizations to litigation, fines, or loss of public‑sector contracts.
---
Formal Requirement Text
> 3.2.3 Consistent Navigation: Navigational mechanisms that are repeated on multiple Web pages within a set of Web pages occur in the same relative order each time they are repeated, unless a change is initiated by the user.
The definition is deliberately narrow: it does not demand identical visual styling, only the same order. However, most accessibility practitioners treat a change in visual placement (e.g., moving a bottom navigation bar to the top on a specific screen) as a violation because it changes the perceived order for users who rely on spatial memory.
---
Common Violations – Mobile & Web
Web Examples
| Violation | Description | Typical Cause | Example Impact |
|---|---|---|---|
| Header reposition | Primary site header appears at the top on most pages but shifts to the bottom on a promotional landing page. | A/B test or special‑case landing page template. | Keyboard users tab through unexpected content; screen‑reader users lose the banner landmark. |
| Conditional footer | Footer navigation links appear only when a user is logged in; anonymous pages lack the footer. | Feature‑gate logic that removes the footer entirely. | Users cannot reach “Help” or “Terms” from logged‑out pages, causing confusion. |
| Dynamic side‑nav order | A sidebar menu reorders its items based on recent usage (e.g., “Profile” moves to top after visiting). | Personalization script that manipulates DOM order. | Users who rely on muscle memory cannot locate “Settings” quickly. |
| Inconsistent breadcrumb | Breadcrumb trail present on product pages but omitted on category pages. | CMS template oversight. | Users lose orientation when navigating back up the hierarchy. |
Mobile Examples
| Violation | Description | Typical Cause | Example Impact |
|---|---|---|---|
| Bottom nav hides on scroll | A bottom navigation bar disappears when scrolling down a list and reappears only at the top. | “Hide on scroll” UI pattern intended to maximize content area. | Users who rely on the bar for quick switches lose it mid‑task; voice‑over focus jumps unpredictably. |
| Drawer vs. tab bar mix | Some screens use a navigation drawer, others use a tab bar, with no clear pattern. | Feature teams implement preferred pattern without central UI guideline. | Users must relearn where to find “Home” on each screen. |
| In‑app toast replaces nav | A full‑width toast covers the bottom navigation temporarily, but the toast does not shift focus away from the nav. | Implementation uses a system overlay without adjusting accessibility traits. | TalkBack users may activate a nav item unintentionally while trying to dismiss the toast. |
| Language switcher moves | A language picker appears in the header on Android but in the settings drawer on iOS for the same app. | Platform‑specific design decisions not aligned. | Bilingual users lose quick access to language change. |
| Modal obscures nav | A modal dialog appears centered, covering the tab bar, but the modal does not trap focus inside it. | Missing focus‑management code. | Keyboard or switch users tab behind the modal, losing context. |
---
Manual Test Steps
Preparation
- Identify the navigation set – Determine which UI components are considered “repeated navigational mechanisms” for the product. Common candidates: header/global nav, footer, side drawer, bottom navigation, tab bar, breadcrumb, skip links, and any persistent floating action button (FAB) that serves as a navigation shortcut.
- Create a reference map – On a baseline screen (e.g., the home screen or a generic content page), record the order, type, and location of each mechanism. Screenshots or a simple spreadsheet help.
- Select user personas – Choose at least three personas that rely on consistency:
- *Keyboard‑only user* (tests tab order and focus visibility).
- *Screen‑reader user* (tests announcement of landmarks and order).
- *Switch‑device or voice‑control user* (tests predictability of activation points).
Execution
| Step | Action | Expected Result | Tools/Notes |
|---|---|---|---|
| 1 | Navigate to the baseline screen. | Record the reference order. | Use a screen‑reader (TalkBack, VoiceOver, NVDA) to hear the sequence. |
| 2 | Move to a second screen that should share the same navigational set (e.g., a product detail page). | The same mechanisms appear in the same order. | Visually inspect; confirm with accessibility inspector (Android Studio, Xcode Accessibility Inspector, Chrome DevTools). |
| 3 | Repeat step 2 for all screens in the set (including error states, empty states, modal backgrounds). | No deviation unless a user‑initiated change (e.g., a user toggles a sidebar). | Log any deviations with screenshot and screen name. |
| 4 | Test keyboard navigation: press Tab repeatedly. | Focus moves through nav items in the reference order, never jumps out of order or skips items. | Use a visible focus outline; ensure no hidden elements receive focus. |
| 5 | Test screen‑reader navigation: swipe or use rotor to jump to headings/landmarks. | Announcements follow the reference order; no unexpected items appear. | Note any extra announcements (e.g., a toast that appears as a navigation item). |
| 6 | Test switch or voice control: issue a command to activate a known nav item (e.g., “Go to Settings”). | The command succeeds on every screen where the item is present. | If the item is missing or misplaced, the command fails or triggers the wrong action. |
| 7 | Test user‑initiated change: open a settings pane that allows the user to hide or reorder nav items. | After the change, the new order is persisted and reflected on all subsequent screens until the user changes it again. | Verify persistence across app restarts or page reloads. |
| 8 | Document findings. | Each deviation is logged as a potential WCAG 3.2.3 failure with severity (usually AA). | Attach steps to reproduce, expected vs. actual order, and impacted personas. |
Edge‑Case Checks
- Conditional rendering: If a nav item is only shown under certain conditions (e.g., admin menu), ensure that when it is hidden, the remaining items retain their original order.
- Overlay content: Modals, tooltips, or snackbars should not be announced as part of the navigation set unless they are intended to be navigational aids.
- Gesture‑based navigation: On iOS, a swipe‑to‑go‑back gesture should not interfere with the perceived order of persistent nav bars.
- Dynamic theming: Dark‑mode or high‑contrast toggles must not reposition nav items; only colors may change.
---
Automated Tools That Check This Criterion
Web
| Tool | How It Checks 3.2.3 | Integration Point | Limitations |
|---|---|---|---|
| axe‑core (Deque) | Provides a rule aria-allowed-attr and custom rules via axe.configure({rules: { 'navigation-order': { enabled: true } }}). Community‑contributed rule sets (e.g., axe-plugin-navigation-order) compare the DOM order of repeated landmarks across pages in a crawl. | CI pipeline (npm script), Jest‑axe, Cypress‑axe, Playwright‑axe. | Requires a defined set of pages to compare; does not detect visual reposition if DOM order unchanged but CSS moves items. |
| WAVE (WebAIM) | Flags “Missing consistent navigation” when a header/footer landmark appears in a different DOM position across scanned pages. | Browser extension, manual testing, API for bulk scans. | Visual‑only shifts may be missed; relies on correct landmark tagging. |
| Lighthouse | Accessibility audit includes a check for “Navigation elements are in a consistent order” based on a sampling of pages during the audit. | Chrome DevTools, CI via lighthouse-ci. | Sampling may miss edge cases; not exhaustive for large sites. |
ESLint plugin eslint-plugin-jsx-a11y | Rule anchor-is-valid and no-noninteractive-tabindex help avoid accidental reordering via tabindex; custom rule can enforce that nav elements appear only once per page or maintain a set order via AST traversal. | Pre‑commit hooks, CI lint stage. | Only works on JSX/HTML source; cannot catch runtime DOM changes caused by JavaScript unless those changes are statically analyzable. |
| Storybook accessibility addon | Renders each story and runs axe; if a story introduces a nav component in a different location, the addon flags it. | Component‑level testing during development. | Does not test assembled pages; relies on component isolation. |
Mobile
| Tool | How It Checks 3.2.3 | Integration Point | Limitations |
|---|---|---|---|
| Android Accessibility Test Framework (ATF) | Custom UIAutomator test can iterate through all activities/fragments, collect the IDs of NavigationView, BottomNavigationView, Toolbar, etc., and assert that the sequence matches a baseline list. | Instrumented test suite, run via Gradle connectedAndroidTest. | Requires maintaining a baseline list; dynamic UI (e.g., conditional visibility) needs extra logic. |
| iOS UI Test with XCTest | Use XCUIApplication to query navigationBars, tabBars, toolbars, and compare their frame.origin or accessibilityElements order across screens. | CI via xcodebuild test. | Sensitive to safe‑area changes; must account for orientation. |
| Google Accessibility Scanner (Android) | Scans screens for missing content descriptions and touch target size; does not directly test order, but can be combined with a custom script that logs the hierarchy and compares order. | Manual or CI via adb shell am broadcast -a com.google.android.apps.accessibility.scanner.SCAN. | No built‑in order rule; needs post‑processing. |
| Apple Accessibility Inspector (Xcode) | Allows manual inspection of the accessibility hierarchy; can export the tree for diff‑based order checking. | Manual QA; can be scripted via xcrun simctl io booted screenshot and xcrun simctl spawn booted log collect. | Export format is verbose; requires parsing. |
| Espresso Idling Resources + custom matcher | Create a matcher that verifies that a specific View with ID nav_home always appears at index 0 within its parent LinearLayout across multiple fragment transactions. | Instrumented tests. | Works best when nav is implemented as static view hierarchy; custom view containers need bespoke matchers. |
| Detox (React Native) | Similar to Espresso; can assert that the navigation component’s testID appears in a predictable order within the root view. | End‑to‑end test suite for RN apps. | Requires consistent testID usage; does not catch native‑only navigation changes. |
> Tip: Combine automated checks with a visual regression tool (e.g., Percy, Applitools) to catch cases where DOM order is correct but CSS visually moves items (e.g., order: 2 in Flexbox).
---
Mobile‑Specific Considerations
Android
- Navigation Component & Jetpack Navigation – If you use the Navigation component, the
NavHosthosts a single<fragment>tag. The bottom nav or drawer is usually defined in the activity layout. Ensure that the activity layout does not change between navigation graph destinations unless the user explicitly opens a settings screen that toggles the nav visibility. - BottomNavigationView – By default, it stays pinned. If you implement
setVisibility(View.GONE)on scroll, provide an accessibility workaround: announce the change viaAccessibilityEvent.TYPE_VIEW_FOCUSEDand keep a persistent “show nav” action accessible via a corner button or voice command. - Navigation Drawer – The drawer should be opened via a consistent gesture (swipe from edge) or a persistent hamburger button. Avoid showing the drawer only on certain screens; if a screen needs full‑width content, consider a modal bottom sheet instead of hiding the drawer.
- Toolbar / AppBar – The title and action items may change, but the
Toolbaritself should remain at the same vertical position (typically top). Useandroid:fitsSystemWindows="true"to keep it stable across different screen cutouts. - Dynamic Feature Modules – When a feature module is loaded at runtime, verify that it does not inject its own nav bar that duplicates or reorders the existing one. Use the
ComponentActivity’ssetContentViewonly once; subsequent modules should add views inside existing containers.
iOS
- UITabBarController – The tab bar should be present in all view controllers that belong to the tab bar’s scope. If you hide it (
tabBar.isHidden = true) for a specific view controller, provide an alternative way to reach the same destinations (e.g., a navigation bar button) and ensure the hidden state is user‑initiated (like a settings toggle). - UINavigationBar – The navigation bar is generally consistent; however, custom
UINavigationBarsubclasses that adjustframe.origin.ybased on content size can cause a shift. Stick to the system bar or useprefersLargeTitleswhich preserves the bar’s position while adjusting title size. - Side Menu (Slide‑out) – Many apps implement a custom side menu using a
UIViewControllercontainment pattern. Ensure the menu’s presenting view controller does not alter the underlying navigation stack order. - Gesture‑Based Navigation – The system swipe‑to‑go‑back gesture should not interfere with a persistent tab bar. If you disable the gesture (
interactivePopGestureRecognizer.isEnabled = false) on certain screens, make sure the back button in the navigation bar remains accessible and in the same location. - Accessibility Traits – For custom nav buttons, set
isAccessibilityElement = trueand assign a meaningfulaccessibilityLabel. Avoid assigning thenavigationBartrait to non‑nav views, as this can confuse VoiceOver’s rotor.
Cross‑Platform (React Native, Flutter, Xamarin)
- React Native – Use
react-native-navigationorreact-native-bottom-tabs. Keep the navigation configuration in a single file (e.g.,AppNavigator.js) and avoid conditional rendering of the navigator based on route params unless the change is user‑driven. - Flutter – The
Scaffoldwidget providesappBar,bottomNavigationBar,drawer, andfloatingActionButton. If you conditionally set any of these tonull, ensure the remaining widgets maintain their order in the widget tree. UseNavigatorobservers to log route changes and assert that the scaffold’s properties are unchanged. - Xamarin.Forms – Prefer
Shellfor a consistent navigation experience. Avoid inserting aNavigationPageinside aContentPagethat already lives inside aShell; that duplication can reorder the back stack.
---
Fixing Violations – Code Examples
Web – Header Reposition
Problem: A promotional page moves the site header to the bottom via a CSS class .promo-header { position: fixed; bottom: 0; }.
Fix: Keep the header in the same DOM location; use a visually distinct promo banner instead of repositioning the header.
<!-- Before (incorrect) -->
<body>
<main>…</main>
<header class="site-header promo-header">…</header>
</body>
<!-- After (correct) -->
<body>
<header class="site-header">…</header>
<main>
<section class="promo-banner">…</section>
…
</main>
</body>
If a visual change is truly needed, ensure the heading order stays the same and add aria-label="Site header" to the header so assistive tech knows its purpose regardless of visual placement.
Web – Conditional Footer
Problem: Footer rendered only when user.isLoggedIn.
Fix: Always render the footer, but hide links that require authentication via aria-disabled="true" or visually hide them with CSS while keeping them in the DOM for screen readers.
<footer>
<nav aria-label="Footer">
<ul>
<li><a href="/help">Help</a></li>
<li><a href="/terms">Terms</a></li>
<li><a href="/login" aria-disabled="{!user.isLoggedIn}">Log In</a></li>
</ul>
</nav>
</footer>
Add CSS:
footer a[aria-disabled="true"] {
pointer-events: none;
opacity: 0.5;
}
Android – Bottom Nav Hide on Scroll
Problem: Using bottomNavigationView.setVisibility(View.GONE) when scrolling a RecyclerView.
Fix: Keep the bottom nav visible at all times. If screen real estate is critical, use a collapsible toolbar that shrinks but does not remove the nav.
// In Activity or Fragment
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// Do NOT hide bottom nav on scroll
// bottomNavigationView.visibility = View.GONE // <-- remove this
// Instead, enable scrolling behavior on the AppBarLayout
val appBarLayout = view.findViewById<AppBarLayout>(R.id.app_bar)
val scrollingView = view.findViewById<RecyclerView>(R.id.recycler_view)
appBarLayout.setScrollingBehavior(scrollingView)
}
If you must hide it for a specific full‑screen dialog, ensure the dialog is a separate DialogFragment that does not sit underneath the nav; the nav stays visible behind the dialog (or you show a temporary “close” button in the dialog’s header).
iOS – Drawer vs. Tab Bar Mix
Problem: Some view controllers present a UITabBarController, others present a custom side‑menu controller.
Fix: Choose one primary navigation pattern for the app and stick to it. If a side menu is needed for certain sections, implement it as a modal presentation that appears *over* the tab bar, not as a replacement.
// In AppDelegate or SceneDelegate
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
let tabBarController = UITabBarController()
// set up tabs…
window?.rootViewController = tabBarController
return true
}
// When presenting side menu:
func showSideMenu() {
let menuVC = SideMenuViewController()
// Present as a form sheet over the existing tab bar
menuVC.modalPresentationStyle = .formSheet
present(menuVC, animated: true, completion: nil)
}
If you must hide the tab bar for a specific screen (e.g., a splash or onboarding), do it only for those screens and restore it immediately after the user leaves them.
Flutter – Conditional hiding should be user‑initiated (e.g., a “Get Started” button that transitions to the main app).
Web – Dynamic Side‑Nav Order
Problem: JavaScript reorders <li> items based on recent clicks.
Fix: Store the order in a persistent setting (e.g., localStorage) and apply it on page load *once*; do not change the order during a session unless the user explicitly opens a settings pane to reorder.
// nav.js
document.addEventListener('DOMContentLoaded', () => {
const nav = document.getElementById('main-nav');
const savedOrder = JSON.parse(localStorage.getItem('navOrder') || '[]');
if (savedOrder.length) {
savedOrder.forEach(id => {
const item = document.getElementById(id);
if (item) nav.appendChild(item); // moves item to end preserving saved order
});
}
});
// Only allow reorder via settings
document.getElementById('reorderBtn').addEventListener('click', () => {
// open a modal that lets user drag & drop; on save, persist new order
});
Mobile – Language Switcher Position
Problem: Android shows language switcher in the toolbar; iOS hides it in Settings.
Fix: Provide a consistent entry point—for example, a floating action button (FAB) labeled “Language” that appears on both platforms and opens a language selection dialog. Keep the platform‑specific entry as a shortcut but do not rely on it as the sole method.
<!-- Android layout -->
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab_language"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_language"
android:contentDescription="@string/change_language"
app:layout_anchorGravity="bottom|end" />
// iOS SwiftUI
struct ContentView: View {
var body: some View {
VStack {
// main content
}
.overlay(
Button(action: { showLanguagePicker() }) {
Image(systemName: "globe")
.accessibilityLabel("Change language")
}
.padding()
, alignment: .bottomTrailing
)
}
}
---
Autonomous Persona‑Driven Exploration – How SUSA Checks This Criterion
SUSA (SUSATest) is an autonomous QA platform that explores an app or web property without pre‑written scripts. It builds a model of the UI by interacting with elements as different personas (curious, impatient, novice, adversarial, elderly, accessibility, power user, etc.). Each persona has a configured behavior profile that influences timing, input patterns, and decision‑making.
Exploration Process Relevant to 3.2.3
- Discovery Phase – SUSA loads the entry point (home screen or URL) and records all *navigation‑related* UI components it can identify via accessibility APIs (Android
AccessibilityNodeInfo, iOSAXUIElement, web ARIA roles/landmarks). It creates a navigation signature – an ordered list of component types and their hierarchical positions (e.g.,[Header → BottomNav → FloatingActionButton]).
- Traversal Phase – For each discovered screen, SUSA repeats a set of actions that mimic each persona:
- *Keyboard‑only persona* sends
TabandShift+Tabevents, logging the focus order. - *Screen‑reader persona* triggers accessibility focus moves (TalkBack/VoiceOver swipe) and captures the spoken labels sequence.
- *Impatient persona* performs rapid taps or clicks to see if UI changes state (e.g., a nav bar hides on scroll).
- *Elderly persona* introduces longer dwell times and deliberate gestures to detect time‑outs or disappearing controls.
- Comparison Logic – After gathering navigation signatures from *N* screens, SUSA computes a similarity score. If any screen’s signature deviates beyond a tolerance (e.g., a missing component, a different order, or a component appearing/disappearing without a user‑initiated toggle), it flags a potential WCAG 3.2.3 violation.
- Persona‑Specific Validation –
- The *accessibility persona* checks that any hidden navigation component is still reachable via a persistent accessibility action (e.g., a “Show menu” button).
- The *power user* persona verifies that muscle‑memory based shortcuts (e.g., double‑tap to jump to Home) work across screens.
- The *adversarial* persona attempts to force UI states (rotation, split‑screen, font scaling) to see if the navigation order remains stable under those conditions.
- Learning & Regression – SUSA stores each navigation signature in a knowledge base. On subsequent runs, it compares the current signature to the stored baseline. If a previously flagged issue is resolved, the status updates to PASS; if a new deviation appears, it is logged as a regression. This cross‑session learning reduces flaky results and helps teams track the impact of refactors or A/B tests.
Why This Approach Beats Simple Rule‑Based Checks
- Dynamic UI – Many apps change navigation based on state (e.g., a modal that slides up from the bottom). SUSA’s interaction‑driven model observes the actual UI after the change, not just the static markup.
- Visual Shifts – By relying on accessibility tree order rather than pixel positions, SUSA catches cases where CSS
orderor transforms move elements without changing the DOM. - Persona Coverage – The same navigation deviation might be invisible to a novice user but block an elderly user who relies on persistent controls. SUSA’s multi‑persona simulation surfaces those nuances automatically.
- Scalability – No need to write and maintain hundreds of test scripts; the platform generates its own exploration paths, adapts to new screens, and learns which areas are stable.
Example Output
[Run 2025-11-02] Navigation Consistency Check
---------------------------------------------
Baseline signature (Home): [Header, BottomNav, FAB]
Screen: ProductDetail
Observed: [Header, FAB] ← BottomNav missing
Impact: Power user cannot switch categories without navigating up.
Verdict: FAIL (WCAG 3.2.3)
Screen: Settings
Observed: [Header, BottomNav, FAB, SettingsToggle] ← SettingsToggle is a user‑initiated toggle, allowed.
Verdict: PASS
The report includes screenshots, the exact accessibility node paths, and suggestions for fixing (e.g., “ensure BottomNav remains visible in all fragments that belong to the main nav set”).
---
Edge Cases That Only Show Up in Production
- Lazy‑Loaded Navigation – Some web apps load the footer via an AJAX call after the initial paint. In a staging environment with throttled network, the footer may appear late, causing automated tools that run before the network settles to miss it. In production, users on slow connections may experience a moment where the navigation set is incomplete, violating 3.2.3 for those users.
- *Mitigation*: Use
MutationObserverorwaitForElementin tests to assert that navigation elements are present within a reasonable timeout (e.g., 2 seconds).
- Conditional Feature Flags – A/B testing frameworks may enable a new navigation variant for a percentage of users. If the flag is evaluated client‑side after DOM construction, some users see the old order while others see the new order, leading to inconsistent experiences.
- *Mitigation*: Treat feature‑flag driven navigation changes as user‑initiated only if the flag is toggled via a explicit settings UI. Otherwise, freeze the flag for the duration of a test session or roll out the change via a server‑side configuration with a clear versioning strategy.
- System UI Overlays – Android’s picture‑in‑picture (PIP) mode or iOS’s slide‑over can temporarily obscure part of the app’s navigation bar. If the app does not adjust the accessible region or provide a way to reach the hidden controls, users relying on the navigation may be stuck.
- *Mitigation*: Listen for
onPictureInPictureModeChanged(Android) orwillMove(toParent:)(iOS) and expose an accessibility action (“Show navigation”) that restores focus to the nav when the overlay hides it.
- Dynamic Font Scaling – Users who increase system font size may cause a navigation bar to wrap or shift vertically. If the bar’s height changes enough to push other content out of the viewport, the perceived order can change for screen‑reader users who rely on spatial proximity.
- *Mitigation*: Use flexible layout constraints (
weight,flex,auto) rather than fixed dimensions, and test with the largest supported font scale.
- Modal Dialogs that Trap Focus Incorrectly – A modal that announces itself as a dialog but does not move focus inside it can cause the navigation order to appear shifted when a screen‑reader user navigates by heading or landmark.
- *Mitigation*: Ensure the modal has
role="dialog"andaria-modal="true"; set initial focus to a focusable element inside the modal (often the close button) and return focus to the triggering element upon dismiss.
- Gesture Navigation Interference – Android’s gesture navigation (swipe up for home, swipe left/right for recent) can conflict with custom edge‑swipe drawers. If the app consumes the edge gesture, the system gesture may be blocked, forcing users to use an alternative navigation method that may be less discoverable.
- *Mitigation*: Follow platform gesture guidelines; reserve edge swipes for system functions or provide a clear, accessible alternative (e.g., a hamburger button).
---
Practical Checklist for Developers & QA
| ✅ Item | Description | How to Verify |
|---|---|---|
| Nav Set Identification | List all UI components that serve as repeated navigation aids (header, footer, side nav, bottom nav, tab bar, breadcrumb, skip links, FAB used for navigation). | Review design specs; run an accessibility scan to harvest landmarks/roles. |
| Baseline Order Capture | Record the order and hierarchy of the nav set on a reference screen (home or generic content page). | Screenshot + accessibility tree export; store as JSON or CSV. |
| Consistency Across Screens | Ensure every screen that belongs to the same logical flow shows the *same* nav set in the *same* order. | Manual navigation; automated crawling with SUSA, axe, or custom UIAutomator/XCTest scripts. |
| User‑Initiated Changes Allowed | If a setting lets the user hide, show, or reorder a nav element, the change must persist and be communicated. | Toggle the setting, navigate to other screens, confirm the new order stays until changed again. |
| No Visual‑Only Reordering | Confirm that CSS transforms, order, flex-direction, or absolute positioning do not change the perceived nav order. |
Test Your App Autonomously
Upload your APK or URL. SUSA explores like 10 real users — finds bugs, accessibility violations, and security issues. No scripts. New to the category? Start with what autonomous product intelligence & QA means.
Try SUSA Free