Pull to refresh (also written pull-to-refresh) is a touch gesture for reloading content: when a scrollable list or feed is already at its top, the user drags it further downward past a threshold and releases it, which triggers a request for new data while a progress indicator appears above the content. In mobile UX, it is one of the most widely recognized patterns for user-initiated updates in feeds, inboxes and lists.
The pattern became popular in iPhone apps around the end of the 2000s and was later adopted by both major platforms as a standard system component. Its strength is that it reuses the scroll gesture the user is already making, so no visible refresh button is needed.
How the pull to refresh gesture works
Pull to refresh relies on overscroll at the top edge of a scroll container. While the list is at offset zero, further downward movement is not used for scrolling; instead the content or an indicator follows the finger with increasing resistance, which communicates that something will happen on release.
The interaction passes through clear states. Crossing a trigger distance, commonly a few tens of density-independent pixels or points, arms the refresh. If the user releases before the threshold, the view springs back without loading. After the request completes, the indicator disappears and new items are inserted at the top.
| State | User action | Visual feedback |
|---|---|---|
| Idle | List rests at the top | No indicator visible |
| Pulling | Drag downward below threshold | Indicator appears, grows or rotates with the drag |
| Armed | Drag beyond the trigger distance | Indicator fully formed, optional haptic tick |
| Refreshing | Finger released | Spinner animates, content stays offset |
| Completed | Data arrives or request fails | Indicator retracts, new items or error message shown |
Platform implementations and parameters
Both mobile platforms provide native components that handle the gesture, physics and accessibility. Using them is usually better than a custom implementation, because they match system behavior that users already expect.
| Platform | Component | Indicator style |
|---|---|---|
| iOS with UIKit | UIRefreshControl attached to a scroll view | Spinner revealed behind the content |
| iOS with SwiftUI | refreshable modifier on a list | System spinner with asynchronous task |
| Android with Views | SwipeRefreshLayout | Circular indicator sliding over content |
| Android with Jetpack Compose | Material pull to refresh container | Material circular indicator |
| Mobile web | Browser native or custom JavaScript | Browser-defined or custom |
Key parameters include the trigger distance, the maximum drag distance, the damping curve that creates resistance and the minimum spinner display time, which prevents a distracting flash when data arrives in a few milliseconds. On the web, the CSS property overscroll-behavior lets developers disable the browser’s own pull to refresh when a page implements its own.
Pull to refresh compared with other update patterns
Pull to refresh is only one way to keep content current. Choosing the right pattern depends on how often data changes and whether the user expects to control updates.
| Pattern | Who triggers it | Best suited for |
|---|---|---|
| Pull to refresh | User, by gesture | Feeds, inboxes, lists updated irregularly |
| Refresh button | User, by tap | Desktop-like tools, accessibility fallback |
| Automatic polling | App, on a timer | Dashboards with predictable change rates |
| Push or live updates | Server, in real time | Chat, live scores, collaboration |
| New items banner | Server, user confirms | Feeds where jumping content would disorient |
Many apps combine patterns: content updates in the background or through push, and pull to refresh remains as a reassurance gesture that lets the user confirm that the list is current.
Designing pull to refresh well
Good implementations make the gesture discoverable, forgiving and honest about progress. The indicator should appear as soon as the pull begins, the threshold should be reachable comfortably within the thumb zone, and the result should be visible.
- Use it only on vertically scrolling lists whose newest content appears at the top.
- Keep the scroll position stable after refresh, inserting new items without throwing the user away from what they were reading.
- Show an error state when the request fails, instead of silently retracting the spinner.
- Offer an alternative action, such as a menu item or button, for users of assistive technology who cannot perform the gesture.
- Avoid conflicts with other vertical gestures, such as a bottom sheet or a swipe-to-dismiss screen.
Accessibility guidelines expect that every gesture has an accessible equivalent. Screen reader users typically cannot drag a list beyond its top, so a refresh action in the accessibility actions or the toolbar is essential.
Common mistakes with pull to refresh
Most problems come from using the pattern where content does not change or from broken feedback. The table lists frequent issues with their causes and fixes.
| Symptom | Cause | Fix |
|---|---|---|
| Page reloads unexpectedly on the web | Browser gesture not disabled | Set overscroll-behavior on the scroll container |
| Spinner never stops | Completion callback not called on error | End refreshing in every code path |
| Spinner flashes briefly | Very fast response | Enforce a short minimum display time |
| Gesture fires while scrolling up quickly | Momentum crosses the threshold | Arm only from a drag that started at the top |
| Users never discover it | Only refresh method on a static screen | Add automatic updates or a visible control |
A subtler mistake is treating pull to refresh as a substitute for correct data synchronization. If an app shows stale content until the user pulls, people learn to refresh compulsively and lose trust in the screen. The gesture works best as a confirmation on top of sensible automatic updates, not as the only path to current data.
The idea in brief
Pull to refresh is the move where you drag a list down with your finger and let go to check for anything new. You see a small spinning circle at the top, and a moment later the newest messages or posts appear.
It works because it feels natural: you are already scrolling up to see the latest items, so pulling a little further means show me more. No extra button is needed, which keeps small screens clean.
A practical scenario
A delivery company builds a mobile app for couriers that shows the list of today’s assigned parcels. Assignments change during the day when dispatchers add stops, so the team adds pull to refresh using the native list components on iOS and Android, together with push notifications for urgent changes.
During testing, couriers in areas with weak signal report that the spinner sometimes keeps turning forever. The developers add a 15-second timeout with a clear error message and a retry option, and they also place a refresh action in the toolbar for screen reader users.
After release, couriers rely on the gesture at each stop to confirm their route, and support calls about missing assignments drop, because the list state is always visible and under their control.