Pull to Refresh
Pull to Refresh
Pull to refresh allows users to update content by pulling down on scrollable areas. This gesture-based interaction has become standard for refreshing feeds, lists, and other updatable content on mobile devices. iOS and Android have native implementations with distinct visual styles that design systems must address.
What Is Pull to Refresh
Pull to refresh enables manual content refresh through a downward drag gesture at the top of scrollable content. When users pull down past a threshold, a loading indicator appears and content refreshes. Release before the threshold cancels the refresh.
The pattern became widespread after Loren Brichter introduced it in the Tweetie app in 2008. Both iOS and Android now provide native pull-to-refresh implementations as standard components.
Native implementations handle the complex gesture recognition, threshold detection, and animation coordination. Custom implementations are possible but require significant effort to match native feel.
How Pull to Refresh Works
iOS uses UIRefreshControl, a standard component that attaches to scroll views. The spinner appears when pulling down, triggers refresh at threshold, and dismisses when refresh completes.
Pull to Refresh Patterns:
iOS UIRefreshControl:
- Standard spinner indicator
- Tint color customizable
- Attached to UIScrollView/UITableView
- Triggers refreshing callback
- Call endRefreshing() when done
SwiftUI:
List {
// content
}
.refreshable {
await refreshContent()
}
Android SwipeRefreshLayout:
- Circular progress indicator
- Color scheme customizable
- Wraps scrollable content
- OnRefreshListener callback
- setRefreshing(false) when done
Compose:
val pullRefreshState = rememberPullRefreshState(
refreshing = isRefreshing,
onRefresh = { refresh() }
)
Box(Modifier.pullRefresh(pullRefreshState)) {
LazyColumn { /* content */ }
PullRefreshIndicator(
refreshing = isRefreshing,
state = pullRefreshState
)
}
Android uses SwipeRefreshLayout, which wraps scrollable content and provides a circular progress indicator. Material Design specifies the indicator’s appearance and behavior.
Gesture mechanics detect pull distance, distinguish refresh pulls from scroll gestures, and animate the indicator’s appearance. Native implementations handle these complexities automatically.
Completion handling requires explicit call to end the refresh state. After content updates, applications must signal completion so the indicator dismisses properly.
Key Considerations
- Native implementations provide expected behavior automatically
- Custom implementations require careful gesture handling
- Indicator styling can be customized within limits
- Completion signaling prevents stuck indicators
- Error handling should dismiss indicator and communicate failure
- Accessibility alternatives may be needed for motor impairments
Common Questions
Should design systems use native or custom pull-to-refresh?
Native implementations are strongly recommended. Pull-to-refresh gesture handling is complex. Native components provide correct behavior that users expect.
Custom implementations add significant complexity. Gesture recognition, threshold detection, rubber-band physics, and animation coordination all require implementation. Getting these wrong creates poor experiences.
Visual customization within native components is usually sufficient. Indicator color, size, and basic styling can be customized. Complete visual overhaul is rarely worth the implementation cost.
Exceptions exist for very specific brand requirements. If brand guidelines absolutely require custom indicators, implementation should carefully match native gesture physics.
How should refresh errors be handled?
Dismiss the indicator when refresh fails. Stuck indicators frustrate users and suggest the application is broken.
Communicate the error appropriately. Toast messages, inline error states, or banner messages can indicate refresh failure.
Maintain existing content when possible. Failed refresh should not clear currently displayed content. Users retain what they had while understanding the update failed.
Provide retry mechanism. Users should be able to attempt refresh again easily, either through another pull or an explicit retry button.
What alternatives exist for users who cannot perform pull gesture?
Explicit refresh button provides non-gesture alternative. A button in the navigation bar or content area enables refresh for users who cannot pull.
Automatic background refresh reduces need for manual refresh. Content that updates automatically requires less user-initiated refresh.
Accessibility services may provide gesture alternatives. VoiceOver and TalkBack have their own interaction models that may address refresh differently.
Design systems should ensure refresh functionality is accessible regardless of motor ability.
Summary
Pull to refresh provides gesture-based content refresh that users expect on mobile devices. Native implementations on iOS (UIRefreshControl) and Android (SwipeRefreshLayout) handle complex gesture mechanics correctly. Design systems should use native components with appropriate customization rather than custom implementations. Error handling must dismiss indicators and communicate failures. Accessibility alternatives ensure all users can refresh content.
Buoy scans your codebase for design system inconsistencies before they ship
Detect Design Drift Free