The States You Forget to Design
Most designers and developers focus on the "happy path" where screens show real data and the connection is fast. But users spend a surprising amount of time looking at empty states, loading indicators, and error messages. These transitional moments shape the perception of your app's quality more than the polished main screens do.
An app with great content screens but poor loading and empty states feels broken. An app with thoughtful transitional states feels fast and polished, even when the network is slow.
Empty States
First-Use Empty State
The user just signed up and has no data yet. This is an onboarding opportunity in disguise. Include a clear illustration that matches your brand, a brief explanation of what this screen shows once populated, and a prominent call-to-action to create the first item. Optionally preview what populated content looks like.
User-Cleared Empty State
The user deleted all items, completed all tasks, or cleared a filter. Acknowledge that the list is intentionally empty (not an error). Provide an action to add new items. For task completion, a congratulatory message works well.
No-Results Empty State
A search or filter returned zero results. This is frustrating and needs careful handling. Acknowledge the search attempt by repeating the query. Suggest corrections (spell check, broader terms). Offer alternative actions like browsing categories or clearing filters. Never show a blank screen.
| Empty State Type | Tone | Primary Action | Secondary Action |
|---|---|---|---|
| First-use | Welcoming, encouraging | Create first item | View tutorial |
| User-cleared | Neutral or congratulatory | Create new item | None needed |
| No-results | Helpful, not apologetic | Modify search/filter | Browse alternatives |
Loading States
Speed Perception Framework
Users perceive loading differently based on visual feedback. Under 100ms feels instant and needs no indicator. Between 100ms and 1 second, a subtle indicator prevents confusion. Between 1 and 10 seconds, skeleton screens or progress indicators are required. Over 10 seconds, show progress percentage, explain the delay, or move to background processing.
Skeleton Screens
Skeleton screens (shimmer UI) show the layout of upcoming content with gray placeholder shapes before real data loads. This is the gold standard for loading states in 2026.
They work because they set expectations about incoming content, feel faster than spinners (the eye perceives progressive loading), and eliminate layout shift when content appears. Match the skeleton to actual layout closely. Use a left-to-right gradient sweep animation. Skip the skeleton if data loads in under 300ms to avoid a flash. Libraries like react-native-skeleton-placeholder, Facebook Shimmer for Android, and Compose shimmer modifiers handle implementation.
Spinner and Progress Indicators
Use spinners only when you cannot predict content layout. Use indeterminate spinners when duration is unknown. Use determinate progress bars for trackable operations (uploads, downloads). Avoid showing a spinner over a blank white screen. Keep previous content visible with the spinner overlaid when possible.
Optimistic Updates
For actions like liking a post, toggling a setting, or sending a message, update the UI immediately and sync with the server in the background. If the request fails, revert and show a brief error. This makes the app feel instant.
Error States
Network Error
Show a clear message ("No internet connection" not a cryptic error code). Provide a retry button. Keep previously loaded content visible when possible. Support offline mode for frequently accessed data.
Server Error
Show user-friendly text, not HTTP status codes. Provide retry. Log technical details for debugging. Consider auto-retry with exponential backoff for temporary failures.
Designing for Slow Connections
Not all users have fast internet. Pre-load content the user is likely to view next. Cache aggressively and show cached data while fetching updates. Use progressive image loading (blur to sharp). Show content as soon as the first piece loads instead of waiting for everything. Indicate staleness with timestamps like "Updated 5 minutes ago."