Scroll-to-top
A way back to the top of a long list, without scrolling all the way up.
Draft
Specified, not implemented yet. The API is described in useScrollToTop and may change.
After the user scrolls far down a long list, a button appears. Tapping it brings the list back to the top, then the button goes away.
Scroll past the dashed line, one screen down, and tap the button. Switch showOn to scroll-up to show it only when the user starts going back up.
When to use it
- Long feeds, search results and catalogs, where going back up by hand takes several flicks.
- Lists that load more pages as the user scrolls (pagination).
A button isn’t the only trigger. On iOS, tapping the status bar scrolls to the top, and on both platforms tapping the tab that is already selected does too. Support these in any case; add the button when the list is long enough to need a visible one.
Don’t add it to lists that fit in one or two screens, or on a screen that already has a floating action button in the same place.
How it works
When the button shows
The button appears only once the top of the list is out of reach. threshold defaults to one screen of content.
scroll-up keeps the content clear while the user reads down, and offers the button when they start looking for the top.
What a tap does
A long animated scroll feels slow and renders every row on the way. Far from the top, the list first jumps without animation, then animates the last screen:
offset 12 000 ──jump──► 800 (threshold) ──animate──► 0
offset 900 ─────────────────────animate─────────► 0The return always takes the same short time, whatever the distance.
| Rule | Why |
|---|---|
Show past threshold | Near the top, the user can scroll back in one flick. |
| Hide while returning | The button did its job. It shouldn’t flash back on the way up. |
| Jump, then animate | A 12 000pt animation is slow and renders every row on the way. |
| A user scroll cancels the return | The user always wins over an animation in progress. |
| Tab press and status bar tap do the same | Users expect them, and they work without a visible button. |
Implementation
Axiom implements it with one hook, useScrollToTop. It tracks the offset and exposes visible and scrollToTop(). The button is yours.
| Library | Used for |
|---|---|
react-native-reanimated | The offset as a shared value, read in useAnimatedScrollHandler. visible is derived on the UI thread and sent to React only when it changes. |
| React Native | scrollToOffset / scrollTo through the list ref for the jump (animated: false) and the return (animated: true). scrollsToTop on iOS for the status bar tap. |
@react-navigation/native (optional) | Its useScrollToTop(ref) scrolls on a tab press. The hook calls it when React Navigation is present. |
In a screen
const top = useScrollToTop();
<Animated.FlatList
data={articles}
renderItem={renderArticle}
{...top.scrollProps}
/>;
{
top.visible && (
<Fab
icon="arrow-up"
accessibilityLabel="Scroll to top"
onPress={top.scrollToTop}
/>
);
}Installation, options and return value are documented in useScrollToTop.
Accessibility
- Give the button a label: “Scroll to top”.
- After the return, move screen reader focus to the first row or the screen title, so the user knows where they are.
- With Reduce Motion on, jump straight to
0without animating. - Don’t rely on the button alone: the tab press and the status bar tap work with a screen reader too.