When async operations — API calls, uploads, data fetches — complete with no visual feedback, users perceive the app as frozen and repeat taps or abandon the action entirely. ISO 25010:2011 performance-efficiency attributes explicitly cover responsiveness perception, and loading indicators are the primary signal that work is in progress. Missing indicators also mask real failures: users cannot distinguish a slow network from a crashed operation, so they have no signal to wait, retry, or report a bug. Custom animations that diverge from platform conventions (native ActivityIndicator on iOS, material progress patterns on Android) erode platform coherence and increase cognitive load without adding value.
Low because the failure is perceptual rather than data-loss or security-impacting — users experience confusion and may repeat actions, but no state is corrupted.
Use React Native's native ActivityIndicator for indeterminate progress and ProgressBar for determinate progress. Gate rendering on the loading boolean from your async state; do not conditionally mount an indicator that is never visible due to broken logic.
import { ActivityIndicator, View } from 'react-native';
export function DataScreen() {
const { data, isLoading, error } = useFetch('/api/items');
if (isLoading) {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<ActivityIndicator size="large" />
</View>
);
}
return <ItemList data={data} />;
}
For uploads or multi-step operations, prefer ProgressBar with a real progress value derived from bytes transferred or steps completed — avoid spinning indefinitely when determinate progress is available.
ID: mobile-ux-patterns.touch-gestures.indicator-conventions
Severity: low
What to look for: Count all async operations (data fetches, API calls, file uploads) and for each, check whether a loading indicator is displayed. Enumerate indicator types used: ActivityIndicator, ProgressBar, or custom.
Pass criteria: At least 90% of async operations show a loading indicator during execution. Indicators use ActivityIndicator for indeterminate progress or ProgressBar for determinate progress. Color and size match platform conventions (subtle on iOS, material design on Android).
Fail criteria: Any async operation has no loading indicator, or indicators use custom implementations that break platform conventions. Must not pass when indicators are present but never shown to users (e.g., conditional rendering logic is broken).
Skip (N/A) when: The app has no async operations or loading states (purely static content).
Detail on fail: Describe indicator deviations. Quote the actual component used. Example: "Loading indicator uses custom animated SVG instead of native ActivityIndicator, breaking platform consistency." or "No loading indicator shown during data fetch �� users see frozen UI."
Remediation: Use native indicators from React Native or platform-specific UI libraries:
import { ActivityIndicator, ProgressBar, View } from 'react-native';
// iOS-style spinner
<ActivityIndicator size="large" color="#0000ff" />
// Android-style progress bar
<ProgressBar progress={0.5} color="#0000ff" />
// Show during async operations
{isLoading && <ActivityIndicator />}